Ruby 4.1.0dev (2026-09-07 revision b57404b461ba8bf34e802d86b0db78388216e182)
string.c (b57404b461ba8bf34e802d86b0db78388216e182)
1/**********************************************************************
2
3 string.c -
4
5 $Author$
6 created at: Mon Aug 9 17:12:58 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
16#include <ctype.h>
17#include <errno.h>
18#include <math.h>
19
20#ifdef HAVE_UNISTD_H
21# include <unistd.h>
22#endif
23
24#include "debug_counter.h"
25#include "encindex.h"
26#include "id.h"
27#include "internal.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"
45#include "probes.h"
46#include "ruby/encoding.h"
47#include "ruby/re.h"
48#include "ruby/thread.h"
49#include "ruby/util.h"
50#include "ruby/ractor.h"
51#include "ruby_assert.h"
52#include "shape.h"
53#include "vm_core.h"
54#include "vm_sync.h"
55#include "zjit.h"
57
58#if defined HAVE_CRYPT_R
59# if defined HAVE_CRYPT_H
60# include <crypt.h>
61# endif
62#elif !defined HAVE_CRYPT
63# include "missing/crypt.h"
64# define HAVE_CRYPT_R 1
65#endif
66
67#undef rb_str_new
68#undef rb_usascii_str_new
69#undef rb_utf8_str_new
70#undef rb_enc_str_new
71#undef rb_str_new_cstr
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
79#undef rb_str_buf_cat
80#undef rb_str_buf_cat2
81#undef rb_str_cat2
82#undef rb_str_cat_cstr
83#undef rb_fstring_cstr
84
87
88/* Flags of RString
89 *
90 * 0: STR_SHARED (equal to ELTS_SHARED)
91 * The string is shared. The buffer this string points to is owned by
92 * another string (the shared root).
93 * 1: RSTRING_NOEMBED
94 * The string is not embedded. When a string is embedded, the contents
95 * follow the header. When a string is not embedded, the contents is
96 * on a separately allocated buffer.
97 * 2: STR_CHILLED (will be frozen in a future version)
98 * The string was allocated as a literal in a file without an explicit `frozen_string_literal` comment.
99 * It emits a deprecation warning when mutated for the first time.
100 * 4: STR_PRECOMPUTED_HASH
101 * The string is embedded and has its precomputed hashcode stored
102 * after the terminator.
103 * 5: STR_SHARED_ROOT
104 * Other strings may point to the contents of this string. When this
105 * flag is set, STR_SHARED must not be set.
106 * 6: STR_BORROWED
107 * When RSTRING_NOEMBED is set and klass is 0, this string is unsafe
108 * to be unshared by rb_str_tmp_frozen_release.
109 * 7: STR_TMPLOCK
110 * The pointer to the buffer is passed to a system call such as
111 * read(2). Any modification and realloc is prohibited.
112 * 8-9: ENC_CODERANGE
113 * Stores the coderange of the string.
114 * 10-16: ENCODING
115 * Stores the encoding of the string.
116 * 17: RSTRING_FSTR
117 * The string is a fstring. The string is deduplicated in the fstring
118 * table.
119 * 18: STR_NOFREE
120 * Do not free this string's buffer when the string is reclaimed
121 * by the garbage collector. Used for when the string buffer is a C
122 * string literal.
123 * 19: STR_FAKESTR
124 * The string is not allocated or managed by the garbage collector.
125 * Typically, the string object header (struct RString) is temporarily
126 * allocated on C stack.
127 */
128
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
135
136#define STR_SET_NOEMBED(str) do {\
137 FL_SET((str), STR_NOEMBED);\
138 FL_UNSET((str), STR_SHARED | STR_SHARED_ROOT | STR_BORROWED);\
139} while (0)
140#define STR_SET_EMBED(str) FL_UNSET((str), STR_NOEMBED | STR_SHARED | STR_NOFREE)
141
142#define STR_SET_LEN(str, n) do { \
143 RSTRING(str)->len = (n); \
144} while (0)
145
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);\
153} while (0)
154
155#define RESIZE_CAPA(str,capacity) do {\
156 const int termlen = TERM_LEN(str);\
157 RESIZE_CAPA_TERM(str,capacity,termlen);\
158} while (0)
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);\
169 }\
170 }\
171 else {\
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);\
176 }\
177} while (0)
178
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) /* for CoW-friendliness */ \
188 FL_SET_RAW((shared_str), STR_BORROWED); \
189 } \
190} while (0)
191
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))
194/* TODO: include the terminator size in capa. */
195
196#define STR_ENC_GET(str) get_encoding(str)
197
198static inline bool
199zero_filled(const char *s, int n)
200{
201 for (; n > 0; --n) {
202 if (*s++) return false;
203 }
204 return true;
205}
206
207#if !defined SHARABLE_MIDDLE_SUBSTRING
208# define SHARABLE_MIDDLE_SUBSTRING 0
209#endif
210
211static inline bool
212SHARABLE_SUBSTRING_P(VALUE str, long beg, long len)
213{
214#if SHARABLE_MIDDLE_SUBSTRING
215 return true;
216#else
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));
220#endif
221}
222
223static inline long
224str_embed_capa(VALUE str)
225{
226 return rb_obj_shape_slot_size(str) - offsetof(struct RString, as.embed.ary);
227}
228
229bool
230rb_str_reembeddable_p(VALUE str)
231{
232 return !FL_TEST(str, STR_NOFREE|STR_SHARED_ROOT|STR_SHARED);
233}
234
235/* True when other strings read this string's bytes out of its own slot, so the slot
236 * contents must stay valid for as long as the object does. */
237bool
238rb_str_embedded_shared_root_p(VALUE str)
239{
240 return STR_EMBED_P(str) && FL_TEST(str, STR_SHARED_ROOT);
241}
242
243static inline size_t
244rb_str_embed_size(long capa, long termlen)
245{
246 size_t size = offsetof(struct RString, as.embed.ary) + capa + termlen;
247 if (size < sizeof(struct RString)) size = sizeof(struct RString);
248 return size;
249}
250
251size_t
252rb_str_size_as_embedded(VALUE str)
253{
254 size_t real_size;
255 if (STR_EMBED_P(str)) {
256 size_t capa = RSTRING(str)->len;
257 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) capa += sizeof(st_index_t);
258
259 real_size = rb_str_embed_size(capa, TERM_LEN(str));
260 }
261 /* if the string is not currently embedded, but it can be embedded, how
262 * much space would it require */
263 else if (rb_str_reembeddable_p(str)) {
264 size_t capa = RSTRING(str)->as.heap.aux.capa;
265 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) capa += sizeof(st_index_t);
266
267 real_size = rb_str_embed_size(capa, TERM_LEN(str));
268 }
269 else {
270 real_size = sizeof(struct RString);
271 }
272
273 return real_size;
274}
275
276static inline bool
277STR_EMBEDDABLE_P(long len, long termlen)
278{
279 return rb_gc_size_allocatable_p(rb_str_embed_size(len, termlen));
280}
281
282/* Substrings and duplicated strings that need a slot larger than this are shared
283 * instead of copied. Larger slots hold fewer objects per page and trigger GC
284 * more often, which outweighs the copy they save; see [Feature #22186] for the
285 * benchmarks. */
286#define STR_COPY_MAX_EMBED_SIZE 256
287
288static VALUE str_replace_shared_without_enc(VALUE str2, VALUE str);
289static VALUE str_new_frozen(VALUE klass, VALUE orig);
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);
292static VALUE str_new(VALUE klass, const char *ptr, long len);
293static void str_make_independent_expand(VALUE str, long len, long expand, const int termlen);
294static inline void str_modifiable(VALUE str);
295static VALUE rb_str_downcase(int argc, VALUE *argv, VALUE str);
296static inline VALUE str_alloc_embed(VALUE klass, size_t capa);
297
298static inline void
299str_make_independent(VALUE str)
300{
301 long len = RSTRING_LEN(str);
302 int termlen = TERM_LEN(str);
303 str_make_independent_expand((str), len, 0L, termlen);
304}
305
306static inline int str_dependent_p(VALUE str);
307
308void
309rb_str_make_independent(VALUE str)
310{
311 if (str_dependent_p(str)) {
312 str_make_independent(str);
313 }
314}
315
316void
317rb_str_make_embedded(VALUE str)
318{
319 RUBY_ASSERT(rb_str_reembeddable_p(str));
320 RUBY_ASSERT(!STR_EMBED_P(str));
321
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;
325 long len = RSTRING(str)->len;
326
327 STR_SET_EMBED(str);
328 STR_SET_LEN(str, len);
329
330 if (len > 0) {
331 memcpy(RSTRING_PTR(str), buf, len);
332 SIZED_FREE_N(buf, old_capa);
333 }
334
335 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
336}
337
338void
339rb_debug_rstring_null_ptr(const char *func)
340{
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",
345 func);
346}
347
348/* symbols for [up|down|swap]case/capitalize options */
349static VALUE sym_ascii, sym_turkic, sym_lithuanian, sym_fold;
350
351static rb_encoding *
352get_encoding(VALUE str)
353{
354 return rb_enc_from_index(ENCODING_GET(str));
355}
356
357static void
358mustnot_broken(VALUE str)
359{
360 if (is_broken_string(str)) {
361 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str)));
362 }
363}
364
365static void
366mustnot_wchar(VALUE str)
367{
368 rb_encoding *enc = STR_ENC_GET(str);
369 if (rb_enc_mbminlen(enc) > 1) {
370 rb_raise(rb_eArgError, "wide char encoding: %s", rb_enc_name(enc));
371 }
372}
373
374static VALUE register_fstring(VALUE str, bool copy, bool force_precompute_hash);
375
376#if SIZEOF_LONG == SIZEOF_VOIDP
377#define PRECOMPUTED_FAKESTR_HASH 1
378#else
379#endif
380
381static inline bool
382BARE_STRING_P(VALUE str)
383{
384 return RBASIC_CLASS(str) == rb_cString && !rb_obj_shape_has_ivars(str);
385}
386
387static inline st_index_t
388str_do_hash(VALUE str)
389{
390 st_index_t h = rb_memhash((const void *)RSTRING_PTR(str), RSTRING_LEN(str));
391 int e = RSTRING_LEN(str) ? ENCODING_GET(str) : 0;
392 if (e && !is_ascii_string(str)) {
393 h = rb_hash_end(rb_hash_uint32(h, (uint32_t)e));
394 }
395 return h;
396}
397
398static VALUE
399str_store_precomputed_hash(VALUE str, st_index_t hash)
400{
401 RUBY_ASSERT(!FL_TEST_RAW(str, STR_PRECOMPUTED_HASH));
402 RUBY_ASSERT(STR_EMBED_P(str));
403
404#if RUBY_DEBUG
405 size_t used_bytes = (RSTRING_LEN(str) + TERM_LEN(str));
406 size_t free_bytes = str_embed_capa(str) - used_bytes;
407 RUBY_ASSERT(free_bytes >= sizeof(st_index_t));
408#endif
409
410 memcpy(RSTRING_END(str) + TERM_LEN(str), &hash, sizeof(hash));
411
412 FL_SET(str, STR_PRECOMPUTED_HASH);
413
414 return str;
415}
416
417VALUE
418rb_fstring(VALUE str)
419{
420 VALUE fstr;
421 int bare;
422
423 Check_Type(str, T_STRING);
424
425 if (FL_TEST(str, RSTRING_FSTR))
426 return str;
427
428 bare = BARE_STRING_P(str);
429 if (!bare) {
430 if (STR_EMBED_P(str)) {
431 OBJ_FREEZE(str);
432 return str;
433 }
434
435 if (FL_TEST_RAW(str, STR_SHARED_ROOT | STR_SHARED) == STR_SHARED_ROOT) {
437 return str;
438 }
439 }
440
441 if (!FL_TEST_RAW(str, FL_FREEZE | STR_NOFREE | STR_CHILLED))
442 rb_str_resize(str, RSTRING_LEN(str));
443
444 fstr = register_fstring(str, false, false);
445
446 if (!bare) {
447 str_replace_shared_without_enc(str, fstr);
448 OBJ_FREEZE(str);
449 return str;
450 }
451 return fstr;
452}
453
454static VALUE fstring_table_obj;
455
456static VALUE
457fstring_concurrent_set_hash(VALUE str)
458{
459#ifdef PRECOMPUTED_FAKESTR_HASH
460 st_index_t h;
461 if (FL_TEST_RAW(str, STR_FAKESTR)) {
462 // register_fstring precomputes the hash and stores it in capa for fake strings
463 h = (st_index_t)RSTRING(str)->as.heap.aux.capa;
464 }
465 else {
466 h = rb_str_hash(str);
467 }
468 // rb_str_hash doesn't include the encoding for ascii only strings, so
469 // we add it to avoid common collisions between `:sym.name` (ASCII) and `"sym"` (UTF-8)
470 return (VALUE)rb_hash_end(rb_hash_uint32(h, (uint32_t)ENCODING_GET_INLINED(str)));
471#else
472 return (VALUE)rb_str_hash(str);
473#endif
474}
475
476static bool
477fstring_concurrent_set_cmp(VALUE a, VALUE b)
478{
479 long alen, blen;
480 const char *aptr, *bptr;
481
484
485 RSTRING_GETMEM(a, aptr, alen);
486 RSTRING_GETMEM(b, bptr, blen);
487 return (alen == blen &&
488 ENCODING_GET(a) == ENCODING_GET(b) &&
489 memcmp(aptr, bptr, alen) == 0);
490}
491
493 bool copy;
494 bool force_precompute_hash;
495};
496
497static VALUE
498fstring_concurrent_set_create(VALUE str, void *data)
499{
500 struct fstr_create_arg *arg = data;
501
502 // Unless the string is empty or binary, its coderange has been precomputed.
503 int coderange = ENC_CODERANGE(str);
504
505 if (FL_TEST_RAW(str, STR_FAKESTR)) {
506 if (arg->copy) {
507 VALUE new_str;
508 long len = RSTRING_LEN(str);
509 long capa = len + sizeof(st_index_t);
510 int term_len = TERM_LEN(str);
511
512 if (arg->force_precompute_hash && STR_EMBEDDABLE_P(capa, term_len)) {
513 new_str = str_alloc_embed(rb_cString, capa + term_len);
514 memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str), len);
515 STR_SET_LEN(new_str, RSTRING_LEN(str));
516 TERM_FILL(RSTRING_END(new_str), TERM_LEN(str));
517 rb_enc_copy(new_str, str);
518 str_store_precomputed_hash(new_str, str_do_hash(str));
519 }
520 else {
521 new_str = str_new(rb_cString, RSTRING(str)->as.heap.ptr, RSTRING(str)->len);
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);
526 }
527#endif
528 }
529 str = new_str;
530 }
531 else {
532 str = str_new_static(rb_cString, RSTRING(str)->as.heap.ptr,
533 RSTRING(str)->len,
534 ENCODING_GET(str));
535 }
536 OBJ_FREEZE(str);
537 }
538 else {
539 if (!OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
540 str = str_new_frozen(rb_cString, str);
541 }
542 if (STR_SHARED_P(str)) { /* str should not be shared */
543 /* shared substring */
544 str_make_independent(str);
546 }
547 if (!BARE_STRING_P(str)) {
548 str = str_new_frozen(rb_cString, str);
549 }
550 }
551
552 ENC_CODERANGE_SET(str, coderange);
553 RBASIC(str)->flags |= RSTRING_FSTR;
554 if (!RB_OBJ_SHAREABLE_P(str)) {
555 RB_OBJ_SET_SHAREABLE(str);
556 }
557 RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
560 RUBY_ASSERT(!FL_TEST_RAW(str, STR_FAKESTR));
561 RUBY_ASSERT(!rb_obj_shape_has_ivars(str));
563 RUBY_ASSERT(!rb_objspace_garbage_object_p(str));
564
565 return str;
566}
567
568static const struct rb_concurrent_set_funcs fstring_concurrent_set_funcs = {
569 .hash = fstring_concurrent_set_hash,
570 .cmp = fstring_concurrent_set_cmp,
571 .create = fstring_concurrent_set_create,
572 .free = NULL,
573};
574
575void
576Init_fstring_table(void)
577{
578 fstring_table_obj = rb_concurrent_set_new(&fstring_concurrent_set_funcs, 8192);
579 rb_gc_register_address(&fstring_table_obj);
580}
581
582static VALUE
583register_fstring(VALUE str, bool copy, bool force_precompute_hash)
584{
585 struct fstr_create_arg args = {
586 .copy = copy,
587 .force_precompute_hash = force_precompute_hash
588 };
589
590#if SIZEOF_VOIDP == SIZEOF_LONG
591 if (FL_TEST_RAW(str, STR_FAKESTR)) {
592 // if the string hasn't been interned, we'll need the hash twice, so we
593 // compute it once and store it in capa
594 RSTRING(str)->as.heap.aux.capa = (long)str_do_hash(str);
595 }
596#endif
597
598 VALUE result = rb_concurrent_set_find_or_insert(&fstring_table_obj, str, &args);
599
600 RUBY_ASSERT(!rb_objspace_garbage_object_p(result));
602 RUBY_ASSERT(OBJ_FROZEN(result));
604 RUBY_ASSERT((rb_gc_verify_shareable(result), 1));
605 RUBY_ASSERT(!FL_TEST_RAW(result, STR_FAKESTR));
607
608 return result;
609}
610
611bool
612rb_obj_is_fstring_table(VALUE obj)
613{
614 ASSERT_vm_locking();
615
616 return obj == fstring_table_obj;
617}
618
619void
620rb_gc_free_fstring(VALUE obj)
621{
622 ASSERT_vm_locking_with_barrier();
623
624 RUBY_ASSERT(FL_TEST(obj, RSTRING_FSTR));
626 RUBY_ASSERT(!FL_TEST(obj, STR_SHARED));
627
628 rb_concurrent_set_delete_by_identity(fstring_table_obj, obj);
629
630 RB_DEBUG_COUNTER_INC(obj_str_fstr);
631
632 FL_UNSET(obj, RSTRING_FSTR);
633}
634
635void
636rb_fstring_foreach_with_replace(int (*callback)(VALUE *str, void *data), void *data)
637{
638 if (fstring_table_obj) {
639 rb_concurrent_set_foreach_with_replace(fstring_table_obj, callback, data);
640 }
641}
642
643static VALUE
644setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx)
645{
646 fake_str->basic.flags = T_STRING|RSTRING_NOEMBED|STR_NOFREE|STR_FAKESTR;
647 RBASIC_SET_FULL_SHAPE_ID((VALUE)fake_str, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
648
649 if (!name) {
651 name = "";
652 }
653
654 ENCODING_SET_INLINED((VALUE)fake_str, encidx);
655
656 RBASIC_SET_CLASS_RAW((VALUE)fake_str, rb_cString);
657 fake_str->len = len;
658 fake_str->as.heap.ptr = (char *)name;
659 fake_str->as.heap.aux.capa = len;
660 return (VALUE)fake_str;
661}
662
663/*
664 * set up a fake string which refers a static string literal.
665 */
666VALUE
667rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc)
668{
669 return setup_fake_str(fake_str, name, len, rb_enc_to_index(enc));
670}
671
672/*
673 * rb_fstring_new and rb_fstring_cstr family create or lookup a frozen
674 * shared string which refers a static string literal. `ptr` must
675 * point a constant string.
676 */
677VALUE
678rb_fstring_new(const char *ptr, long len)
679{
680 struct RString fake_str = {RBASIC_INIT};
681 return register_fstring(setup_fake_str(&fake_str, ptr, len, ENCINDEX_US_ASCII), false, false);
682}
683
684VALUE
685rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc)
686{
687 struct RString fake_str = {RBASIC_INIT};
688 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), false, false);
689}
690
691VALUE
692rb_fstring_cstr(const char *ptr)
693{
694 return rb_fstring_new(ptr, strlen(ptr));
695}
696
697static inline bool
698single_byte_optimizable(VALUE str)
699{
700 int encindex = ENCODING_GET(str);
701 switch (encindex) {
702 case ENCINDEX_ASCII_8BIT:
703 case ENCINDEX_US_ASCII:
704 return true;
705 case ENCINDEX_UTF_8:
706 // For UTF-8 it's worth scanning the string coderange when unknown.
707 return rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT;
708 }
709 /* Conservative. It may be ENC_CODERANGE_UNKNOWN. */
710 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
711 return true;
712 }
713
714 if (rb_enc_mbmaxlen(rb_enc_from_index(encindex)) == 1) {
715 return true;
716 }
717
718 /* Conservative. Possibly single byte.
719 * "\xa1" in Shift_JIS for example. */
720 return false;
721}
722
724
725static inline const char *
726search_nonascii(const char *p, const char *e)
727{
728 const char *s, *t;
729
730 if (p < e && !ISASCII(*p)) {
731 return p;
732 }
733
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)
739# else
740# error "don't know what to do."
741# endif
742#else
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 /* or...? */
747# else
748# error "don't know what to do."
749# endif
750#endif
751
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;
756 p += l;
757 switch (l) {
758 default: UNREACHABLE;
759#if SIZEOF_VOIDP > 4
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;
764#endif
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;
768 case 0: break;
769 }
770 }
771#endif
772#if defined(HAVE_BUILTIN___BUILTIN_ASSUME_ALIGNED) &&! UNALIGNED_WORD_ACCESS
773#define aligned_ptr(value) \
774 __builtin_assume_aligned((value), sizeof(uintptr_t))
775#else
776#define aligned_ptr(value) (value)
777#endif
778 s = aligned_ptr(p);
779 t = (e - (SIZEOF_VOIDP-1));
780#undef aligned_ptr
781 for (;s < t; s += sizeof(uintptr_t)) {
782 uintptr_t word;
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);
787#else
788 return (const char *)s + (ntz_intptr(word&NONASCII_MASK)>>3);
789#endif
790 }
791 }
792 p = (const char *)s;
793 }
794
795 switch (e - p) {
796 default: UNREACHABLE;
797#if SIZEOF_VOIDP > 4
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;
802#endif
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;
806 case 0: return NULL;
807 }
808}
809
810static int
811coderange_scan(const char *p, long len, rb_encoding *enc)
812{
813 const char *e = p + len;
814
815 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
816 /* enc is ASCII-8BIT. ASCII-8BIT string never be broken. */
817 p = search_nonascii(p, e);
819 }
820
821 if (rb_enc_asciicompat(enc)) {
822 p = search_nonascii(p, e);
823 if (!p) return ENC_CODERANGE_7BIT;
824 for (;;) {
825 int ret = rb_enc_precise_mbclen(p, e, enc);
827 p += MBCLEN_CHARFOUND_LEN(ret);
828 if (p == e) break;
829 p = search_nonascii(p, e);
830 if (!p) break;
831 }
832 }
833 else {
834 while (p < e) {
835 int ret = rb_enc_precise_mbclen(p, e, enc);
837 p += MBCLEN_CHARFOUND_LEN(ret);
838 }
839 }
840 return ENC_CODERANGE_VALID;
841}
842
843long
844rb_str_coderange_scan_restartable(const char *s, const char *e, rb_encoding *enc, int *cr)
845{
846 const char *p = s;
847
848 if (*cr == ENC_CODERANGE_BROKEN)
849 return e - s;
850
851 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
852 /* enc is ASCII-8BIT. ASCII-8BIT string never be broken. */
853 if (*cr == ENC_CODERANGE_VALID) return e - s;
854 p = search_nonascii(p, e);
856 return e - s;
857 }
858 else if (rb_enc_asciicompat(enc)) {
859 p = search_nonascii(p, e);
860 if (!p) {
861 if (*cr != ENC_CODERANGE_VALID) *cr = ENC_CODERANGE_7BIT;
862 return e - s;
863 }
864 for (;;) {
865 int ret = rb_enc_precise_mbclen(p, e, enc);
866 if (!MBCLEN_CHARFOUND_P(ret)) {
868 return p - s;
869 }
870 p += MBCLEN_CHARFOUND_LEN(ret);
871 if (p == e) break;
872 p = search_nonascii(p, e);
873 if (!p) break;
874 }
875 }
876 else {
877 while (p < e) {
878 int ret = rb_enc_precise_mbclen(p, e, enc);
879 if (!MBCLEN_CHARFOUND_P(ret)) {
881 return p - s;
882 }
883 p += MBCLEN_CHARFOUND_LEN(ret);
884 }
885 }
887 return e - s;
888}
889
890static inline void
891str_enc_copy(VALUE str1, VALUE str2)
892{
893 rb_enc_set_index(str1, ENCODING_GET(str2));
894}
895
896/* Like str_enc_copy, but does not check frozen status of str1.
897 * You should use this only if you're certain that str1 is not frozen. */
898static inline void
899str_enc_copy_direct(VALUE str1, VALUE str2)
900{
901 int inlined_encoding = RB_ENCODING_GET_INLINED(str2);
902 if (inlined_encoding == ENCODING_INLINE_MAX) {
903 rb_enc_set_index(str1, rb_enc_get_index(str2));
904 }
905 else {
906 ENCODING_SET_INLINED(str1, inlined_encoding);
907 }
908}
909
910static void
911rb_enc_cr_str_copy_for_substr(VALUE dest, VALUE src)
912{
913 /* this function is designed for copying encoding and coderange
914 * from src to new string "dest" which is made from the part of src.
915 */
916 str_enc_copy(dest, src);
917 if (RSTRING_LEN(dest) == 0) {
918 if (!rb_enc_asciicompat(STR_ENC_GET(src)))
920 else
922 return;
923 }
924 switch (ENC_CODERANGE(src)) {
927 break;
929 if (!rb_enc_asciicompat(STR_ENC_GET(src)) ||
930 search_nonascii(RSTRING_PTR(dest), RSTRING_END(dest)))
932 else
934 break;
935 default:
936 break;
937 }
938}
939
940static void
941rb_enc_cr_str_exact_copy(VALUE dest, VALUE src)
942{
943 str_enc_copy(dest, src);
945}
946
947static int
948enc_coderange_scan(VALUE str, rb_encoding *enc)
949{
950 return coderange_scan(RSTRING_PTR(str), RSTRING_LEN(str), enc);
951}
952
953int
954rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc)
955{
956 return enc_coderange_scan(str, enc);
957}
958
959int
960rbimpl_enc_str_coderange_scan(VALUE str)
961{
962 int cr = enc_coderange_scan(str, get_encoding(str));
963 ENC_CODERANGE_SET(str, cr);
964 return cr;
965}
966
967#undef rb_enc_str_coderange
968int
969rb_enc_str_coderange(VALUE str)
970{
971 int cr = ENC_CODERANGE(str);
972
973 if (cr == ENC_CODERANGE_UNKNOWN) {
974 cr = rbimpl_enc_str_coderange_scan(str);
975 }
976 return cr;
977}
978#define rb_enc_str_coderange rb_enc_str_coderange_inline
979
980static inline bool
981rb_enc_str_asciicompat(VALUE str)
982{
983 int encindex = ENCODING_GET_INLINED(str);
984 return rb_str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
985}
986
987int
989{
990 switch(ENC_CODERANGE(str)) {
992 return rb_enc_str_asciicompat(str) && is_ascii_string(str);
994 return true;
995 default:
996 return false;
997 }
998}
999
1000static inline void
1001str_mod_check(VALUE s, const char *p, long len)
1002{
1003 if (RSTRING_PTR(s) != p || RSTRING_LEN(s) != len){
1004 rb_raise(rb_eRuntimeError, "string modified");
1005 }
1006}
1007
1008static size_t
1009str_capacity(VALUE str, const int termlen)
1010{
1011 if (STR_EMBED_P(str)) {
1012 return str_embed_capa(str) - termlen;
1013 }
1014 else if (FL_ANY_RAW(str, STR_SHARED|STR_NOFREE)) {
1015 return RSTRING(str)->len;
1016 }
1017 else {
1018 return RSTRING(str)->as.heap.aux.capa;
1019 }
1020}
1021
1022size_t
1024{
1025 return str_capacity(str, TERM_LEN(str));
1026}
1027
1028static inline void
1029must_not_null(const char *ptr)
1030{
1031 if (!ptr) {
1032 rb_raise(rb_eArgError, "NULL pointer given");
1033 }
1034}
1035
1036static inline VALUE
1037str_alloc_embed(VALUE klass, size_t capa)
1038{
1039 size_t size = rb_str_embed_size(capa, 0);
1040 RUBY_ASSERT(size > 0);
1041 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
1042
1043 NEWOBJ_OF(str, struct RString, klass, T_STRING, size);
1044
1045 str->len = 0;
1046 str->as.embed.ary[0] = 0;
1047
1048 return (VALUE)str;
1049}
1050
1051static inline VALUE
1052str_alloc_heap(VALUE klass)
1053{
1054 NEWOBJ_OF(str, struct RString, klass, T_STRING | STR_NOEMBED, sizeof(struct RString));
1055
1056 str->len = 0;
1057 str->as.heap.aux.capa = 0;
1058 str->as.heap.ptr = NULL;
1059
1060 return (VALUE)str;
1061}
1062
1063static inline VALUE
1064empty_str_alloc(VALUE klass)
1065{
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));
1070 return str;
1071}
1072
1073static VALUE
1074str_enc_new(VALUE klass, const char *ptr, long len, rb_encoding *enc)
1075{
1076 VALUE str;
1077
1078 if (len < 0) {
1079 rb_raise(rb_eArgError, "negative string size (or size too big)");
1080 }
1081
1082 if (enc == NULL) {
1083 enc = rb_ascii8bit_encoding();
1084 }
1085
1086 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1087
1088 int termlen = rb_enc_mbminlen(enc);
1089
1090 if (STR_EMBEDDABLE_P(len, termlen)) {
1091 str = str_alloc_embed(klass, len + termlen);
1092 if (len == 0) {
1093 ENC_CODERANGE_SET(str, rb_enc_asciicompat(enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
1094 }
1095 }
1096 else {
1097 str = str_alloc_heap(klass);
1098 RSTRING(str)->as.heap.aux.capa = len;
1099 /* :FIXME: @shyouhei guesses `len + termlen` is guaranteed to never
1100 * integer overflow. If we can STATIC_ASSERT that, the following
1101 * mul_add_mul can be reverted to a simple ALLOC_N. */
1102 RSTRING(str)->as.heap.ptr =
1103 rb_xmalloc_mul_add_mul(sizeof(char), len, sizeof(char), termlen);
1104 }
1105
1106 rb_enc_raw_set(str, enc);
1107
1108 if (ptr) {
1109 memcpy(RSTRING_PTR(str), ptr, len);
1110 }
1111 else {
1112 memset(RSTRING_PTR(str), 0, len);
1113 }
1114
1115 STR_SET_LEN(str, len);
1116 TERM_FILL(RSTRING_PTR(str) + len, termlen);
1117 return str;
1118}
1119
1120static VALUE
1121str_new(VALUE klass, const char *ptr, long len)
1122{
1123 return str_enc_new(klass, ptr, len, rb_ascii8bit_encoding());
1124}
1125
1126VALUE
1127rb_str_new(const char *ptr, long len)
1128{
1129 return str_new(rb_cString, ptr, len);
1130}
1131
1132VALUE
1133rb_usascii_str_new(const char *ptr, long len)
1134{
1135 return str_enc_new(rb_cString, ptr, len, rb_usascii_encoding());
1136}
1137
1138VALUE
1139rb_utf8_str_new(const char *ptr, long len)
1140{
1141 return str_enc_new(rb_cString, ptr, len, rb_utf8_encoding());
1142}
1143
1144VALUE
1145rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
1146{
1147 return str_enc_new(rb_cString, ptr, len, enc);
1148}
1149
1150VALUE
1152{
1153 must_not_null(ptr);
1154 /* rb_str_new_cstr() can take pointer from non-malloc-generated
1155 * memory regions, and that cannot be detected by the MSAN. Just
1156 * trust the programmer that the argument passed here is a sane C
1157 * string. */
1158 __msan_unpoison_string(ptr);
1159 return rb_str_new(ptr, strlen(ptr));
1160}
1161
1162VALUE
1164{
1165 return rb_enc_str_new_cstr(ptr, rb_usascii_encoding());
1166}
1167
1168VALUE
1170{
1171 return rb_enc_str_new_cstr(ptr, rb_utf8_encoding());
1172}
1173
1174VALUE
1176{
1177 must_not_null(ptr);
1178 if (rb_enc_mbminlen(enc) != 1) {
1179 rb_raise(rb_eArgError, "wchar encoding given");
1180 }
1181 return rb_enc_str_new(ptr, strlen(ptr), enc);
1182}
1183
1184static VALUE
1185str_new_static(VALUE klass, const char *ptr, long len, int encindex)
1186{
1187 VALUE str;
1188
1189 if (len < 0) {
1190 rb_raise(rb_eArgError, "negative string size (or size too big)");
1191 }
1192
1193 if (!ptr) {
1194 str = str_enc_new(klass, ptr, len, rb_enc_from_index(encindex));
1195 }
1196 else {
1197 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1198 str = str_alloc_heap(klass);
1199 RSTRING(str)->len = len;
1200 RSTRING(str)->as.heap.ptr = (char *)ptr;
1201 RSTRING(str)->as.heap.aux.capa = len;
1202 RBASIC(str)->flags |= STR_NOFREE;
1203 rb_enc_associate_index(str, encindex);
1204 }
1205 return str;
1206}
1207
1208VALUE
1209rb_str_new_static(const char *ptr, long len)
1210{
1211 return str_new_static(rb_cString, ptr, len, 0);
1212}
1213
1214/* Take an xmalloc'd buffer as the String's body without copying it; the String owns it
1215 * from here and frees it like any other heap string. ptr must hold capa bytes plus the
1216 * terminator for encindex, which is what a Ractor courier's string node carries. */
1217VALUE
1218rb_str_new_owned(char *ptr, long len, long capa, int encindex)
1219{
1220 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1221 VALUE str = str_alloc_heap(rb_cString);
1222 RSTRING(str)->len = len;
1223 RSTRING(str)->as.heap.ptr = ptr;
1224 /* Freed by size (STR_HEAP_SIZE = capa + terminator), so capa must describe the
1225 * allocation the caller made, not just the bytes in use. */
1226 RSTRING(str)->as.heap.aux.capa = capa;
1227 rb_enc_associate_index(str, encindex);
1228 return str;
1229}
1230
1231VALUE
1233{
1234 return str_new_static(rb_cString, ptr, len, ENCINDEX_US_ASCII);
1235}
1236
1237VALUE
1239{
1240 return str_new_static(rb_cString, ptr, len, ENCINDEX_UTF_8);
1241}
1242
1243VALUE
1245{
1246 return str_new_static(rb_cString, ptr, len, rb_enc_to_index(enc));
1247}
1248
1249static VALUE str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len,
1250 rb_encoding *from, rb_encoding *to,
1251 int ecflags, VALUE ecopts);
1252
1253static inline bool
1254is_enc_ascii_string(VALUE str, rb_encoding *enc)
1255{
1256 int encidx = rb_enc_to_index(enc);
1257 if (rb_enc_get_index(str) == encidx)
1258 return is_ascii_string(str);
1259 return enc_coderange_scan(str, enc) == ENC_CODERANGE_7BIT;
1260}
1261
1262VALUE
1263rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
1264{
1265 long len;
1266 const char *ptr;
1267 VALUE newstr;
1268
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) {
1275 str = rb_str_dup(str);
1276 rb_enc_associate(str, to);
1277 }
1278 return str;
1279 }
1280
1281 RSTRING_GETMEM(str, ptr, len);
1282 newstr = str_cat_conv_enc_opts(rb_str_buf_new(len), 0, ptr, len,
1283 from, to, ecflags, ecopts);
1284 if (NIL_P(newstr)) {
1285 /* some error, return original */
1286 return str;
1287 }
1288 return newstr;
1289}
1290
1291VALUE
1292rb_str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len,
1293 rb_encoding *from, int ecflags, VALUE ecopts)
1294{
1295 long olen;
1296
1297 olen = RSTRING_LEN(newstr);
1298 if (ofs < -olen || olen < ofs)
1299 rb_raise(rb_eIndexError, "index %ld out of string", ofs);
1300 if (ofs < 0) ofs += olen;
1301 if (!from) {
1302 STR_SET_LEN(newstr, ofs);
1303 return rb_str_cat(newstr, ptr, len);
1304 }
1305
1306 rb_str_modify(newstr);
1307 return str_cat_conv_enc_opts(newstr, ofs, ptr, len, from,
1308 rb_enc_get(newstr),
1309 ecflags, ecopts);
1310}
1311
1312VALUE
1313rb_str_initialize(VALUE str, const char *ptr, long len, rb_encoding *enc)
1314{
1315 STR_SET_LEN(str, 0);
1316 rb_enc_associate(str, enc);
1317 rb_str_cat(str, ptr, len);
1318 return str;
1319}
1320
1321static VALUE
1322str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len,
1323 rb_encoding *from, rb_encoding *to,
1324 int ecflags, VALUE ecopts)
1325{
1326 rb_econv_t *ec;
1328 long olen;
1329 VALUE econv_wrapper;
1330 const unsigned char *start, *sp;
1331 unsigned char *dest, *dp;
1332 size_t converted_output = (size_t)ofs;
1333
1334 olen = rb_str_capacity(newstr);
1335
1336 econv_wrapper = rb_obj_alloc(rb_cEncodingConverter);
1337 RBASIC_CLEAR_CLASS(econv_wrapper);
1338 ec = rb_econv_open_opts(from->name, to->name, ecflags, ecopts);
1339 if (!ec) return Qnil;
1340 DATA_PTR(econv_wrapper) = ec;
1341
1342 sp = (unsigned char*)ptr;
1343 start = sp;
1344 while ((dest = (unsigned char*)RSTRING_PTR(newstr)),
1345 (dp = dest + converted_output),
1346 (ret = rb_econv_convert(ec, &sp, start + len, &dp, dest + olen, 0)),
1348 /* destination buffer short */
1349 size_t converted_input = sp - start;
1350 size_t rest = len - converted_input;
1351 converted_output = dp - dest;
1352 rb_str_set_len(newstr, converted_output);
1353 if (converted_input && converted_output &&
1354 rest < (LONG_MAX / converted_output)) {
1355 rest = (rest * converted_output) / converted_input;
1356 }
1357 else {
1358 rest = olen;
1359 }
1360 olen += rest < 2 ? 2 : rest;
1361 rb_str_resize(newstr, olen);
1362 }
1363 DATA_PTR(econv_wrapper) = 0;
1364 RB_GC_GUARD(econv_wrapper);
1365 rb_econv_close(ec);
1366 switch (ret) {
1367 case econv_finished:
1368 len = dp - (unsigned char*)RSTRING_PTR(newstr);
1369 rb_str_set_len(newstr, len);
1370 rb_enc_associate(newstr, to);
1371 return newstr;
1372
1373 default:
1374 return Qnil;
1375 }
1376}
1377
1378VALUE
1380{
1381 return rb_str_conv_enc_opts(str, from, to, 0, Qnil);
1382}
1383
1384VALUE
1386{
1387 rb_encoding *ienc;
1388 VALUE str;
1389 const int eidx = rb_enc_to_index(eenc);
1390
1391 if (!ptr) {
1392 return rb_enc_str_new(ptr, len, eenc);
1393 }
1394
1395 /* ASCII-8BIT case, no conversion */
1396 if ((eidx == rb_ascii8bit_encindex()) ||
1397 (eidx == rb_usascii_encindex() && search_nonascii(ptr, ptr + len))) {
1398 return rb_str_new(ptr, len);
1399 }
1400 /* no default_internal or same encoding, no conversion */
1401 ienc = rb_default_internal_encoding();
1402 if (!ienc || eenc == ienc) {
1403 return rb_enc_str_new(ptr, len, eenc);
1404 }
1405 /* ASCII compatible, and ASCII only string, no conversion in
1406 * default_internal */
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);
1411 }
1412 /* convert from the given encoding to default_internal */
1413 str = rb_enc_str_new(NULL, 0, ienc);
1414 /* when the conversion failed for some reason, just ignore the
1415 * default_internal and result in the given encoding as-is. */
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);
1418 }
1419 return str;
1420}
1421
1422VALUE
1423rb_external_str_with_enc(VALUE str, rb_encoding *eenc)
1424{
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());
1429 return str;
1430 }
1431 rb_enc_associate_index(str, eidx);
1432 return rb_str_conv_enc(str, eenc, rb_default_internal_encoding());
1433}
1434
1435VALUE
1436rb_external_str_new(const char *ptr, long len)
1437{
1438 return rb_external_str_new_with_enc(ptr, len, rb_default_external_encoding());
1439}
1440
1441VALUE
1443{
1444 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_default_external_encoding());
1445}
1446
1447VALUE
1448rb_locale_str_new(const char *ptr, long len)
1449{
1450 return rb_external_str_new_with_enc(ptr, len, rb_locale_encoding());
1451}
1452
1453VALUE
1455{
1456 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_locale_encoding());
1457}
1458
1459VALUE
1461{
1462 return rb_external_str_new_with_enc(ptr, len, rb_filesystem_encoding());
1463}
1464
1465VALUE
1467{
1468 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_filesystem_encoding());
1469}
1470
1471VALUE
1473{
1474 return rb_str_export_to_enc(str, rb_default_external_encoding());
1475}
1476
1477VALUE
1479{
1480 return rb_str_export_to_enc(str, rb_locale_encoding());
1481}
1482
1483VALUE
1485{
1486 return rb_str_conv_enc(str, STR_ENC_GET(str), enc);
1487}
1488
1489static VALUE
1490str_replace_shared_without_enc(VALUE str2, VALUE str)
1491{
1492 const int termlen = TERM_LEN(str);
1493 char *ptr;
1494 long len;
1495
1496 RSTRING_GETMEM(str, ptr, len);
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);
1502 }
1503 else {
1504 VALUE root;
1505 if (STR_SHARED_P(str)) {
1506 root = RSTRING(str)->as.heap.aux.shared;
1507 RSTRING_GETMEM(str, ptr, len);
1508 }
1509 else {
1510 root = rb_str_new_frozen(str);
1511 RSTRING_GETMEM(root, ptr, len);
1512 }
1513 RUBY_ASSERT(OBJ_FROZEN(root));
1514
1515 if (!STR_EMBED_P(str2) && !FL_TEST_RAW(str2, STR_SHARED|STR_NOFREE)) {
1516 if (FL_TEST_RAW(str2, STR_SHARED_ROOT)) {
1517 rb_fatal("about to free a possible shared root");
1518 }
1519 char *ptr2 = STR_HEAP_PTR(str2);
1520 if (ptr2 != ptr) {
1521 SIZED_FREE_N(ptr2, STR_HEAP_SIZE(str2));
1522 }
1523 }
1524 FL_SET(str2, STR_NOEMBED);
1525 RSTRING(str2)->as.heap.ptr = ptr;
1526 STR_SET_SHARED(str2, root);
1527 }
1528
1529 STR_SET_LEN(str2, len);
1530
1531 return str2;
1532}
1533
1534static VALUE
1535str_replace_shared(VALUE str2, VALUE str)
1536{
1537 str_replace_shared_without_enc(str2, str);
1538 rb_enc_cr_str_exact_copy(str2, str);
1539 return str2;
1540}
1541
1542static VALUE
1543str_new_shared(VALUE klass, VALUE str)
1544{
1545 return str_replace_shared(str_alloc_heap(klass), str);
1546}
1547
1548VALUE
1550{
1551 return str_new_shared(rb_obj_class(str), str);
1552}
1553
1554VALUE
1556{
1557 if (RB_FL_TEST_RAW(orig, FL_FREEZE | STR_CHILLED) == FL_FREEZE) return orig;
1558 return str_new_frozen(rb_obj_class(orig), orig);
1559}
1560
1561static VALUE
1562rb_str_new_frozen_String(VALUE orig)
1563{
1564 if (OBJ_FROZEN(orig) && rb_obj_class(orig) == rb_cString) return orig;
1565 return str_new_frozen(rb_cString, orig);
1566}
1567
1568
1569VALUE
1570rb_str_frozen_bare_string(VALUE orig)
1571{
1572 if (RB_LIKELY(BARE_STRING_P(orig) && OBJ_FROZEN_RAW(orig))) return orig;
1573 return str_new_frozen(rb_cString, orig);
1574}
1575
1576VALUE
1577rb_str_tmp_frozen_acquire(VALUE orig)
1578{
1579 if (OBJ_FROZEN_RAW(orig)) return orig;
1580 return str_new_frozen_buffer(0, orig, FALSE);
1581}
1582
1583VALUE
1584rb_str_tmp_frozen_no_embed_acquire(VALUE orig)
1585{
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);
1588
1589 VALUE str = str_alloc_heap(0);
1590 OBJ_FREEZE(str);
1591 /* Always set the STR_SHARED_ROOT to ensure it does not get re-embedded. */
1592 FL_SET(str, STR_SHARED_ROOT);
1593
1594 size_t capa = str_capacity(orig, TERM_LEN(orig));
1595
1596 /* If the string is embedded then we want to create a copy that is heap
1597 * allocated. If the string is shared then the shared root must be
1598 * embedded, so we want to create a copy. If the string is a shared root
1599 * then it must be embedded, so we want to create a copy. */
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));
1602 memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), capa);
1603 }
1604 else {
1605 /* orig must be heap allocated and not shared, so we can safely transfer
1606 * the pointer to str. */
1607 RSTRING(str)->as.heap.ptr = RSTRING(orig)->as.heap.ptr;
1608 RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1609 RBASIC(orig)->flags &= ~STR_NOFREE;
1610 STR_SET_SHARED(orig, str);
1611 if (RB_OBJ_SHAREABLE_P(orig)) {
1612 RB_OBJ_SET_SHAREABLE(str);
1613 RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
1614 }
1615 }
1616
1617 RSTRING(str)->len = RSTRING(orig)->len;
1618 RSTRING(str)->as.heap.aux.capa = capa + (TERM_LEN(orig) - TERM_LEN(str));
1619
1620 return str;
1621}
1622
1623void
1624rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
1625{
1626 if (RBASIC_CLASS(tmp) != 0)
1627 return;
1628
1629 if (STR_EMBED_P(tmp)) {
1631 }
1632 else if (FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_TMPLOCK &&
1633 !OBJ_FROZEN_RAW(orig)) {
1634 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1635
1636 if (shared == tmp && !FL_TEST_RAW(tmp, STR_BORROWED)) {
1637 RUBY_ASSERT(RSTRING(orig)->as.heap.ptr == RSTRING(tmp)->as.heap.ptr);
1638 RUBY_ASSERT(RSTRING_LEN(orig) == RSTRING_LEN(tmp));
1639
1640 /* Unshare orig since the root (tmp) only has this one child. */
1641 FL_UNSET_RAW(orig, STR_SHARED);
1642 RSTRING(orig)->as.heap.aux.capa = RSTRING(tmp)->as.heap.aux.capa;
1643 RBASIC(orig)->flags |= RBASIC(tmp)->flags & STR_NOFREE;
1645
1646 /* Make tmp embedded and empty so it is safe for sweeping. */
1647 STR_SET_EMBED(tmp);
1648 STR_SET_LEN(tmp, 0);
1649 }
1650 }
1651}
1652
1653static VALUE
1654str_new_frozen(VALUE klass, VALUE orig)
1655{
1656 return str_new_frozen_buffer(klass, orig, TRUE);
1657}
1658
1659static VALUE
1660heap_str_make_shared(VALUE klass, VALUE orig)
1661{
1662 RUBY_ASSERT(!STR_EMBED_P(orig));
1663 RUBY_ASSERT(!STR_SHARED_P(orig));
1665
1666 VALUE str = str_alloc_heap(klass);
1667 STR_SET_LEN(str, RSTRING_LEN(orig));
1668 RSTRING(str)->as.heap.ptr = RSTRING_PTR(orig);
1669 RSTRING(str)->as.heap.aux.capa = RSTRING(orig)->as.heap.aux.capa;
1670 RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1671 RBASIC(orig)->flags &= ~STR_NOFREE;
1672 STR_SET_SHARED(orig, str);
1673 if (klass == 0)
1674 FL_UNSET_RAW(str, STR_BORROWED);
1675 return str;
1676}
1677
1678static VALUE
1679str_new_frozen_buffer(VALUE klass, VALUE orig, int copy_encoding)
1680{
1681 VALUE str;
1682
1683 long len = RSTRING_LEN(orig);
1684 rb_encoding *enc = copy_encoding ? STR_ENC_GET(orig) : rb_ascii8bit_encoding();
1685 int termlen = copy_encoding ? TERM_LEN(orig) : 1;
1686
1687 if (STR_EMBED_P(orig) || STR_EMBEDDABLE_P(len, termlen)) {
1688 str = str_enc_new(klass, RSTRING_PTR(orig), len, enc);
1689 RUBY_ASSERT(STR_EMBED_P(str));
1690 }
1691 else {
1692 if (FL_TEST_RAW(orig, STR_SHARED)) {
1693 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1694 long ofs = RSTRING(orig)->as.heap.ptr - RSTRING_PTR(shared);
1695 long rest = RSTRING_LEN(shared) - ofs - RSTRING_LEN(orig);
1696 RUBY_ASSERT(ofs >= 0);
1697 RUBY_ASSERT(rest >= 0);
1698 RUBY_ASSERT(ofs + rest <= RSTRING_LEN(shared));
1700
1701 if ((ofs > 0) || (rest > 0) ||
1702 (klass != RBASIC(shared)->klass) ||
1703 ENCODING_GET(shared) != ENCODING_GET(orig)) {
1704 str = str_new_shared(klass, shared);
1705 RUBY_ASSERT(!STR_EMBED_P(str));
1706 RSTRING(str)->as.heap.ptr += ofs;
1707 STR_SET_LEN(str, RSTRING_LEN(str) - (ofs + rest));
1708 }
1709 else {
1710 if (RBASIC_CLASS(shared) == 0)
1711 FL_SET_RAW(shared, STR_BORROWED);
1712 return shared;
1713 }
1714 }
1715 else if (STR_EMBEDDABLE_P(RSTRING_LEN(orig), TERM_LEN(orig))) {
1716 str = str_alloc_embed(klass, RSTRING_LEN(orig) + TERM_LEN(orig));
1717 STR_SET_EMBED(str);
1718 memcpy(RSTRING_PTR(str), RSTRING_PTR(orig), RSTRING_LEN(orig));
1719 STR_SET_LEN(str, RSTRING_LEN(orig));
1720 ENC_CODERANGE_SET(str, ENC_CODERANGE(orig));
1721 TERM_FILL(RSTRING_END(str), TERM_LEN(orig));
1722 }
1723 else {
1724 if (RB_OBJ_SHAREABLE_P(orig)) {
1725 str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
1726 }
1727 else {
1728 str = heap_str_make_shared(klass, orig);
1729 }
1730 }
1731 }
1732
1733 if (copy_encoding) rb_enc_cr_str_exact_copy(str, orig);
1734 OBJ_FREEZE(str);
1735 return str;
1736}
1737
1738VALUE
1739rb_str_new_with_class(VALUE obj, const char *ptr, long len)
1740{
1741 return str_enc_new(rb_obj_class(obj), ptr, len, STR_ENC_GET(obj));
1742}
1743
1744static VALUE
1745str_new_empty_String(VALUE str)
1746{
1747 VALUE v = rb_str_new(0, 0);
1748 rb_enc_copy(v, str);
1749 return v;
1750}
1751
1752#define STR_BUF_MIN_SIZE 63
1753
1754VALUE
1756{
1757 if (STR_EMBEDDABLE_P(capa, 1)) {
1758 return str_alloc_embed(rb_cString, capa + 1);
1759 }
1760
1761 VALUE str = str_alloc_heap(rb_cString);
1762
1763 RSTRING(str)->as.heap.aux.capa = capa;
1764 RSTRING(str)->as.heap.ptr = ALLOC_N(char, (size_t)capa + 1);
1765 RSTRING(str)->as.heap.ptr[0] = '\0';
1766
1767 return str;
1768}
1769
1770VALUE
1772{
1773 VALUE str;
1774 long len = strlen(ptr);
1775
1776 str = rb_str_buf_new(len);
1777 rb_str_buf_cat(str, ptr, len);
1778
1779 return str;
1780}
1781
1782VALUE
1784{
1785 return str_new(0, 0, len);
1786}
1787
1788void
1790{
1791 if (STR_EMBED_P(str)) {
1792 RB_DEBUG_COUNTER_INC(obj_str_embed);
1793 }
1794 else if (FL_TEST(str, STR_SHARED | STR_NOFREE)) {
1795 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_SHARED));
1796 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_NOFREE));
1797 }
1798 else {
1799 RB_DEBUG_COUNTER_INC(obj_str_ptr);
1800 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
1801 }
1802}
1803
1804size_t
1805rb_str_memsize(VALUE str)
1806{
1807 if (FL_TEST(str, STR_NOEMBED|STR_SHARED|STR_NOFREE) == STR_NOEMBED) {
1808 return STR_HEAP_SIZE(str);
1809 }
1810 else {
1811 return 0;
1812 }
1813}
1814
1815VALUE
1817{
1818 return rb_convert_type_with_id(str, T_STRING, "String", idTo_str);
1819}
1820
1821static inline void str_discard(VALUE str);
1822static void str_shared_replace(VALUE str, VALUE str2);
1823
1824void
1826{
1827 if (str != str2) str_shared_replace(str, str2);
1828}
1829
1830static void
1831str_shared_replace(VALUE str, VALUE str2)
1832{
1833 rb_encoding *enc;
1834 int cr;
1835 int termlen;
1836
1837 RUBY_ASSERT(str2 != str);
1838 enc = STR_ENC_GET(str2);
1839 cr = ENC_CODERANGE(str2);
1840 str_discard(str);
1841 termlen = rb_enc_mbminlen(enc);
1842
1843 STR_SET_LEN(str, RSTRING_LEN(str2));
1844
1845 if (str_embed_capa(str) >= RSTRING_LEN(str2) + termlen) {
1846 STR_SET_EMBED(str);
1847 memcpy(RSTRING_PTR(str), RSTRING_PTR(str2), (size_t)RSTRING_LEN(str2) + termlen);
1848 rb_enc_associate(str, enc);
1849 ENC_CODERANGE_SET(str, cr);
1850 }
1851 else {
1852 if (STR_EMBED_P(str2)) {
1853 RUBY_ASSERT(!FL_TEST(str2, STR_SHARED));
1854 long len = RSTRING_LEN(str2);
1855 RUBY_ASSERT(len + termlen <= str_embed_capa(str2));
1856
1857 char *new_ptr = ALLOC_N(char, len + termlen);
1858 memcpy(new_ptr, RSTRING(str2)->as.embed.ary, len + termlen);
1859 RSTRING(str2)->as.heap.ptr = new_ptr;
1860 STR_SET_LEN(str2, len);
1861 RSTRING(str2)->as.heap.aux.capa = len;
1862 STR_SET_NOEMBED(str2);
1863 }
1864
1865 STR_SET_NOEMBED(str);
1866 FL_UNSET(str, STR_SHARED);
1867 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1868
1869 if (FL_TEST(str2, STR_SHARED)) {
1870 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1871 STR_SET_SHARED(str, shared);
1872 }
1873 else {
1874 RSTRING(str)->as.heap.aux.capa = RSTRING(str2)->as.heap.aux.capa;
1875 }
1876
1877 /* abandon str2 */
1878 STR_SET_EMBED(str2);
1879 RSTRING_PTR(str2)[0] = 0;
1880 STR_SET_LEN(str2, 0);
1881 rb_enc_associate(str, enc);
1882 ENC_CODERANGE_SET(str, cr);
1883 }
1884}
1885
1886VALUE
1888{
1889 VALUE str;
1890
1891 if (RB_TYPE_P(obj, T_STRING)) {
1892 return obj;
1893 }
1894 str = rb_funcall(obj, idTo_s, 0);
1895 return rb_obj_as_string_result(str, obj);
1896}
1897
1898VALUE
1899rb_obj_as_string_result(VALUE str, VALUE obj)
1900{
1901 if (!RB_TYPE_P(str, T_STRING))
1902 return rb_any_to_s(obj);
1903 return str;
1904}
1905
1906static VALUE
1907str_replace(VALUE str, VALUE str2)
1908{
1909 long len;
1910
1911 len = RSTRING_LEN(str2);
1912 if (STR_SHARED_P(str2)) {
1913 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1915 STR_SET_NOEMBED(str);
1916 STR_SET_LEN(str, len);
1917 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1918 STR_SET_SHARED(str, shared);
1919 rb_enc_cr_str_exact_copy(str, str2);
1920 }
1921 else {
1922 str_replace_shared(str, str2);
1923 }
1924
1925 return str;
1926}
1927
1928static inline VALUE
1929ec_str_alloc_embed(struct rb_execution_context_struct *ec, VALUE klass, size_t capa)
1930{
1931 size_t size = rb_str_embed_size(capa, 0);
1932 RUBY_ASSERT(size > 0);
1933 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
1934
1935 EC_NEWOBJ_OF(str, struct RString, klass, T_STRING, size, ec);
1936
1937 str->len = 0;
1938
1939 return (VALUE)str;
1940}
1941
1942static inline VALUE
1943ec_str_alloc_heap(struct rb_execution_context_struct *ec, VALUE klass)
1944{
1945 EC_NEWOBJ_OF(str, struct RString, klass, T_STRING | STR_NOEMBED, sizeof(struct RString), ec);
1946
1947 str->as.heap.aux.capa = 0;
1948 str->as.heap.ptr = NULL;
1949
1950 return (VALUE)str;
1951}
1952
1953static inline void
1954str_duplicate_setup_encoding(VALUE str, VALUE dup, VALUE flags)
1955{
1956 int encidx = 0;
1957 if ((flags & ENCODING_MASK) == (ENCODING_INLINE_MAX<<ENCODING_SHIFT)) {
1958 encidx = rb_enc_get_index(str);
1959 flags &= ~ENCODING_MASK;
1960 }
1961 FL_SET_RAW(dup, flags & ~FL_FREEZE);
1962 if (encidx) rb_enc_associate_index(dup, encidx);
1963}
1964
1965static const VALUE flag_mask = ENC_CODERANGE_MASK | ENCODING_MASK | FL_FREEZE;
1966
1967static inline void
1968str_duplicate_setup_embed(VALUE klass, VALUE str, VALUE dup)
1969{
1970 VALUE flags = FL_TEST_RAW(str, flag_mask);
1971 long len = RSTRING_LEN(str);
1972
1973 RUBY_ASSERT(STR_EMBED_P(dup));
1974 RUBY_ASSERT(str_embed_capa(dup) >= len + TERM_LEN(str));
1975 MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + TERM_LEN(str));
1976 STR_SET_LEN(dup, RSTRING_LEN(str));
1977 str_duplicate_setup_encoding(str, dup, flags);
1978}
1979
1980static inline void
1981str_duplicate_setup_heap(VALUE klass, VALUE str, VALUE dup)
1982{
1983 VALUE flags = FL_TEST_RAW(str, flag_mask);
1984 VALUE root = str;
1985 if (FL_TEST_RAW(str, STR_SHARED)) {
1986 root = RSTRING(str)->as.heap.aux.shared;
1987 }
1988 else if (UNLIKELY(!OBJ_FROZEN_RAW(str))) {
1989 root = str = str_new_frozen(klass, str);
1990 flags = FL_TEST_RAW(str, flag_mask);
1991 }
1992 RUBY_ASSERT(!STR_SHARED_P(root));
1994
1995 RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
1996 FL_SET_RAW(dup, RSTRING_NOEMBED);
1997 STR_SET_SHARED(dup, root);
1998 flags |= RSTRING_NOEMBED | STR_SHARED;
1999
2000 STR_SET_LEN(dup, RSTRING_LEN(str));
2001 str_duplicate_setup_encoding(str, dup, flags);
2002}
2003
2004static inline VALUE
2005str_duplicate(VALUE klass, VALUE str)
2006{
2007 VALUE dup;
2008 if (STR_EMBED_P(str) && rb_str_embed_size(RSTRING_LEN(str), 1) <= STR_COPY_MAX_EMBED_SIZE) {
2009 dup = str_alloc_embed(klass, RSTRING_LEN(str) + TERM_LEN(str));
2010
2011 str_duplicate_setup_embed(klass, str, dup);
2012 }
2013 else {
2014 dup = str_alloc_heap(klass);
2015
2016 str_duplicate_setup_heap(klass, str, dup);
2017 }
2018
2019 return dup;
2020}
2021
2022VALUE
2024{
2025 return str_duplicate(rb_obj_class(str), str);
2026}
2027
2028/* :nodoc: */
2029VALUE
2030rb_str_dup_m(VALUE str)
2031{
2032 if (LIKELY(BARE_STRING_P(str))) {
2033 return str_duplicate(rb_cString, str);
2034 }
2035 else {
2036 return rb_obj_dup(str);
2037 }
2038}
2039
2040VALUE
2042{
2043 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2044 return str_duplicate(rb_cString, str);
2045}
2046
2047VALUE
2048rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled)
2049{
2050 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2051 VALUE new_str, klass = rb_cString;
2052
2053 if (!(chilled && RTEST(rb_ivar_defined(str, id_debug_created_info))) && STR_EMBED_P(str)) {
2054 new_str = ec_str_alloc_embed(ec, klass, RSTRING_LEN(str) + TERM_LEN(str));
2055 str_duplicate_setup_embed(klass, str, new_str);
2056 }
2057 else {
2058 new_str = ec_str_alloc_heap(ec, klass);
2059 str_duplicate_setup_heap(klass, str, new_str);
2060 }
2061 if (chilled) {
2062 FL_SET_RAW(new_str, STR_CHILLED);
2063 }
2064 return new_str;
2065}
2066
2067#if USE_ZJIT
2068bool
2069rb_zjit_str_resurrect_fastpath(VALUE str, bool chilled, size_t *size_out,
2070 VALUE *flags_out,
2071 long *len_out, size_t *byte_size_out)
2072{
2073 if (chilled && RTEST(rb_ivar_defined(str, id_debug_created_info))) return false;
2074
2075 if (!STR_EMBED_P(str)) return false;
2076
2077 long len = RSTRING_LEN(str);
2078 long termlen = TERM_LEN(str);
2079 size_t size = rb_str_embed_size(len + termlen, 0);
2080 if (!rb_gc_size_allocatable_p(size)) return false;
2081
2082 VALUE flags = FL_TEST_RAW(str, flag_mask);
2083
2084 if ((flags & ENCODING_MASK) == ((VALUE)ENCODING_INLINE_MAX << ENCODING_SHIFT)) {
2085 return false;
2086 }
2087
2088 flags &= ~FL_FREEZE;
2089 flags |= T_STRING;
2090 if (chilled) flags |= STR_CHILLED;
2091
2092 *size_out = size;
2093 *flags_out = flags;
2094 *len_out = len;
2095 *byte_size_out = (size_t)(len + termlen);
2096 return true;
2097}
2098#endif
2099
2100VALUE
2101rb_str_with_debug_created_info(VALUE str, VALUE path, int line)
2102{
2103 VALUE debug_info = rb_ary_new_from_args(2, path, INT2FIX(line));
2104 if (OBJ_FROZEN_RAW(str)) str = rb_str_dup(str);
2105 rb_ivar_set(str, id_debug_created_info, rb_ary_freeze(debug_info));
2106 FL_SET_RAW(str, STR_CHILLED);
2107 return rb_str_freeze(str);
2108}
2109
2110/*
2111 * The documentation block below uses an include (instead of inline text)
2112 * because the included text has non-ASCII characters (which are not allowed in a C file).
2113 */
2114
2115/*
2116 *
2117 * call-seq:
2118 * String.new(string = ''.encode(Encoding::ASCII_8BIT) , **options) -> new_string
2119 *
2120 * :include: doc/string/new.rdoc
2121 *
2122 */
2123
2124static VALUE
2125rb_str_init(int argc, VALUE *argv, VALUE str)
2126{
2127 static ID keyword_ids[2];
2128 VALUE orig, opt, venc, vcapa;
2129 VALUE kwargs[2];
2130 rb_encoding *enc = 0;
2131 int n;
2132
2133 if (!keyword_ids[0]) {
2134 keyword_ids[0] = rb_id_encoding();
2135 CONST_ID(keyword_ids[1], "capacity");
2136 }
2137
2138 n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2139 if (!NIL_P(opt)) {
2140 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2141 venc = kwargs[0];
2142 vcapa = kwargs[1];
2143 if (!UNDEF_P(venc) && !NIL_P(venc)) {
2144 enc = rb_to_encoding(venc);
2145 }
2146 if (!UNDEF_P(vcapa) && !NIL_P(vcapa)) {
2147 long capa = NUM2LONG(vcapa);
2148 long len = 0;
2149 int termlen = enc ? rb_enc_mbminlen(enc) : 1;
2150
2151 if (capa < STR_BUF_MIN_SIZE) {
2152 capa = STR_BUF_MIN_SIZE;
2153 }
2154 if (n == 1) {
2155 StringValue(orig);
2156 len = RSTRING_LEN(orig);
2157 if (capa < len) {
2158 capa = len;
2159 }
2160 if (orig == str) n = 0;
2161 }
2162 str_modifiable(str);
2163 if (STR_EMBED_P(str) || FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2164 /* make noembed always */
2165 const size_t size = (size_t)capa + termlen;
2166 const char *const old_ptr = RSTRING_PTR(str);
2167 const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
2168 char *new_ptr = ALLOC_N(char, size);
2169 if (STR_EMBED_P(str)) RUBY_ASSERT((long)osize <= str_embed_capa(str));
2170 memcpy(new_ptr, old_ptr, osize < size ? osize : size);
2171 FL_UNSET_RAW(str, STR_SHARED|STR_NOFREE);
2172 RSTRING(str)->as.heap.ptr = new_ptr;
2173 }
2174 else if (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
2175 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
2176 (size_t)capa + termlen, STR_HEAP_SIZE(str));
2177 }
2178 STR_SET_LEN(str, len);
2179 TERM_FILL(&RSTRING(str)->as.heap.ptr[len], termlen);
2180 if (n == 1) {
2181 memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), len);
2182 rb_enc_cr_str_exact_copy(str, orig);
2183 }
2184 FL_SET(str, STR_NOEMBED);
2185 RSTRING(str)->as.heap.aux.capa = capa;
2186 }
2187 else if (n == 1) {
2188 rb_str_replace(str, orig);
2189 }
2190 if (enc) {
2191 rb_enc_associate(str, enc);
2193 }
2194 }
2195 else if (n == 1) {
2196 rb_str_replace(str, orig);
2197 }
2198 return str;
2199}
2200
2201/* :nodoc: */
2202static VALUE
2203rb_str_s_new(int argc, VALUE *argv, VALUE klass)
2204{
2205 if (klass != rb_cString) {
2206 return rb_class_new_instance_pass_kw(argc, argv, klass);
2207 }
2208
2209 static ID keyword_ids[2];
2210 VALUE orig, opt, encoding = Qnil, capacity = Qnil;
2211 VALUE kwargs[2];
2212 rb_encoding *enc = NULL;
2213
2214 int n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2215 if (NIL_P(opt)) {
2216 return rb_class_new_instance_pass_kw(argc, argv, klass);
2217 }
2218
2219 keyword_ids[0] = rb_id_encoding();
2220 CONST_ID(keyword_ids[1], "capacity");
2221 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2222 encoding = kwargs[0];
2223 capacity = kwargs[1];
2224
2225 if (n == 1) {
2226 orig = StringValue(orig);
2227 }
2228 else {
2229 orig = Qnil;
2230 }
2231
2232 if (UNDEF_P(encoding)) {
2233 if (!NIL_P(orig)) {
2234 encoding = rb_obj_encoding(orig);
2235 }
2236 }
2237
2238 if (!UNDEF_P(encoding)) {
2239 enc = rb_to_encoding(encoding);
2240 }
2241
2242 // If capacity is nil, we're basically just duping `orig`.
2243 if (UNDEF_P(capacity)) {
2244 if (NIL_P(orig)) {
2245 VALUE empty_str = str_new(klass, "", 0);
2246 if (enc) {
2247 rb_enc_associate(empty_str, enc);
2248 }
2249 return empty_str;
2250 }
2251 VALUE copy = str_duplicate(klass, orig);
2252 rb_enc_associate(copy, enc);
2253 ENC_CODERANGE_CLEAR(copy);
2254 return copy;
2255 }
2256
2257 long capa = 0;
2258 capa = NUM2LONG(capacity);
2259 if (capa < 0) {
2260 capa = 0;
2261 }
2262
2263 if (!NIL_P(orig)) {
2264 long orig_capa = rb_str_capacity(orig);
2265 if (orig_capa > capa) {
2266 capa = orig_capa;
2267 }
2268 }
2269
2270 VALUE str = str_enc_new(klass, NULL, capa, enc);
2271 STR_SET_LEN(str, 0);
2272 TERM_FILL(RSTRING_PTR(str), enc ? rb_enc_mbmaxlen(enc) : 1);
2273
2274 if (!NIL_P(orig)) {
2275 rb_str_buf_append(str, orig);
2276 }
2277
2278 return str;
2279}
2280
2281#ifdef NONASCII_MASK
2282#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2283
2284/*
2285 * UTF-8 leading bytes have either 0xxxxxxx or 11xxxxxx
2286 * bit representation. (see https://en.wikipedia.org/wiki/UTF-8)
2287 * Therefore, the following pseudocode can detect UTF-8 leading bytes.
2288 *
2289 * if (!(byte & 0x80))
2290 * byte |= 0x40; // turn on bit6
2291 * return ((byte>>6) & 1); // bit6 represent whether this byte is leading or not.
2292 *
2293 * This function calculates whether a byte is leading or not for all bytes
2294 * in the argument word by concurrently using the above logic, and then
2295 * adds up the number of leading bytes in the word.
2296 */
2297static inline uintptr_t
2298count_utf8_lead_bytes_with_word(const uintptr_t *s)
2299{
2300 uintptr_t d = *s;
2301
2302 /* Transform so that bit0 indicates whether we have a UTF-8 leading byte or not. */
2303 d = (d>>6) | (~d>>7);
2304 d &= NONASCII_MASK >> 7;
2305
2306 /* Gather all bytes. */
2307#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2308 /* use only if it can use POPCNT */
2309 return rb_popcount_intptr(d);
2310#else
2311 d += (d>>8);
2312 d += (d>>16);
2313# if SIZEOF_VOIDP == 8
2314 d += (d>>32);
2315# endif
2316 return (d&0xF);
2317#endif
2318}
2319#endif
2320
2321static inline long
2322enc_strlen(const char *p, const char *e, rb_encoding *enc, int cr)
2323{
2324 long c;
2325 const char *q;
2326
2327 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2328 long diff = (long)(e - p);
2329 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2330 }
2331#ifdef NONASCII_MASK
2332 else if (cr == ENC_CODERANGE_VALID && enc == rb_utf8_encoding()) {
2333 uintptr_t len = 0;
2334 if ((int)sizeof(uintptr_t) * 2 < e - p) {
2335 const uintptr_t *s, *t;
2336 const uintptr_t lowbits = sizeof(uintptr_t) - 1;
2337 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2338 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
2339 while (p < (const char *)s) {
2340 if (is_utf8_lead_byte(*p)) len++;
2341 p++;
2342 }
2343 while (s < t) {
2344 len += count_utf8_lead_bytes_with_word(s);
2345 s++;
2346 }
2347 p = (const char *)s;
2348 }
2349 while (p < e) {
2350 if (is_utf8_lead_byte(*p)) len++;
2351 p++;
2352 }
2353 return (long)len;
2354 }
2355#endif
2356 else if (rb_enc_asciicompat(enc)) {
2357 c = 0;
2358 if (ENC_CODERANGE_CLEAN_P(cr)) {
2359 while (p < e) {
2360 q = search_nonascii(p, e);
2361 if (!q)
2362 return c + (e - p);
2363 c += q - p;
2364 p = q;
2365 p += rb_enc_fast_mbclen(p, e, enc);
2366 c++;
2367 }
2368 }
2369 else {
2370 while (p < e) {
2371 q = search_nonascii(p, e);
2372 if (!q)
2373 return c + (e - p);
2374 c += q - p;
2375 p = q;
2376 p += rb_enc_mbclen(p, e, enc);
2377 c++;
2378 }
2379 }
2380 return c;
2381 }
2382
2383 for (c=0; p<e; c++) {
2384 p += rb_enc_mbclen(p, e, enc);
2385 }
2386 return c;
2387}
2388
2389long
2390rb_enc_strlen(const char *p, const char *e, rb_encoding *enc)
2391{
2392 return enc_strlen(p, e, enc, ENC_CODERANGE_UNKNOWN);
2393}
2394
2395/* To get strlen with cr
2396 * Note that given cr is not used.
2397 */
2398long
2399rb_enc_strlen_cr(const char *p, const char *e, rb_encoding *enc, int *cr)
2400{
2401 long c;
2402 const char *q;
2403 int ret;
2404
2405 *cr = 0;
2406 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2407 long diff = (long)(e - p);
2408 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2409 }
2410 else if (rb_enc_asciicompat(enc)) {
2411 c = 0;
2412 while (p < e) {
2413 q = search_nonascii(p, e);
2414 if (!q) {
2415 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2416 return c + (e - p);
2417 }
2418 c += q - p;
2419 p = q;
2420 ret = rb_enc_precise_mbclen(p, e, enc);
2421 if (MBCLEN_CHARFOUND_P(ret)) {
2422 *cr |= ENC_CODERANGE_VALID;
2423 p += MBCLEN_CHARFOUND_LEN(ret);
2424 }
2425 else {
2427 p++;
2428 }
2429 c++;
2430 }
2431 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2432 return c;
2433 }
2434
2435 for (c=0; p<e; c++) {
2436 ret = rb_enc_precise_mbclen(p, e, enc);
2437 if (MBCLEN_CHARFOUND_P(ret)) {
2438 *cr |= ENC_CODERANGE_VALID;
2439 p += MBCLEN_CHARFOUND_LEN(ret);
2440 }
2441 else {
2443 if (p + rb_enc_mbminlen(enc) <= e)
2444 p += rb_enc_mbminlen(enc);
2445 else
2446 p = e;
2447 }
2448 }
2449 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2450 return c;
2451}
2452
2453/* enc must be str's enc or rb_enc_check(str, str2) */
2454static long
2455str_strlen(VALUE str, rb_encoding *enc)
2456{
2457 const char *p, *e;
2458 int cr;
2459
2460 if (single_byte_optimizable(str)) return RSTRING_LEN(str);
2461 if (!enc) enc = STR_ENC_GET(str);
2462 p = RSTRING_PTR(str);
2463 e = RSTRING_END(str);
2464 cr = ENC_CODERANGE(str);
2465
2466 if (cr == ENC_CODERANGE_UNKNOWN) {
2467 long n = rb_enc_strlen_cr(p, e, enc, &cr);
2468 if (cr) ENC_CODERANGE_SET(str, cr);
2469 return n;
2470 }
2471 else {
2472 return enc_strlen(p, e, enc, cr);
2473 }
2474}
2475
2476long
2478{
2479 return str_strlen(str, NULL);
2480}
2481
2482/*
2483 * call-seq:
2484 * length -> integer
2485 *
2486 * :include: doc/string/length.rdoc
2487 *
2488 */
2489
2490VALUE
2492{
2493 return LONG2NUM(str_strlen(str, NULL));
2494}
2495
2496/*
2497 * call-seq:
2498 * bytesize -> integer
2499 *
2500 * :include: doc/string/bytesize.rdoc
2501 *
2502 */
2503
2504VALUE
2505rb_str_bytesize(VALUE str)
2506{
2507 return LONG2NUM(RSTRING_LEN(str));
2508}
2509
2510/*
2511 * call-seq:
2512 * empty? -> true or false
2513 *
2514 * Returns whether the length of +self+ is zero:
2515 *
2516 * 'hello'.empty? # => false
2517 * ' '.empty? # => false
2518 * ''.empty? # => true
2519 *
2520 * Related: see {Querying}[rdoc-ref:String@Querying].
2521 */
2522
2523static VALUE
2524rb_str_empty(VALUE str)
2525{
2526 return RBOOL(RSTRING_LEN(str) == 0);
2527}
2528
2529/*
2530 * call-seq:
2531 * self + other_string -> new_string
2532 *
2533 * Returns a new string containing +other_string+ concatenated to +self+:
2534 *
2535 * 'Hello from ' + self.to_s # => "Hello from main"
2536 *
2537 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2538 */
2539
2540VALUE
2542{
2543 VALUE str3;
2544 rb_encoding *enc;
2545 const char *ptr1, *ptr2;
2546 char *ptr3;
2547 long len1, len2;
2548 int termlen;
2549
2550 StringValue(str2);
2551 enc = rb_enc_check_str(str1, str2);
2552 RSTRING_GETMEM(str1, ptr1, len1);
2553 RSTRING_GETMEM(str2, ptr2, len2);
2554 termlen = rb_enc_mbminlen(enc);
2555 if (len1 > LONG_MAX - len2) {
2556 rb_raise(rb_eArgError, "string size too big");
2557 }
2558 str3 = str_enc_new(rb_cString, 0, len1+len2, enc);
2559 ptr3 = RSTRING_PTR(str3);
2560 memcpy(ptr3, ptr1, len1);
2561 memcpy(ptr3+len1, ptr2, len2);
2562 TERM_FILL(&ptr3[len1+len2], termlen);
2563
2564 ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
2566 RB_GC_GUARD(str1);
2567 RB_GC_GUARD(str2);
2568 return str3;
2569}
2570
2571/* A variant of rb_str_plus that does not raise but return Qundef instead. */
2572VALUE
2573rb_str_opt_plus(VALUE str1, VALUE str2)
2574{
2577 long len1, len2;
2578 MAYBE_UNUSED(char) *ptr1, *ptr2;
2579 RSTRING_GETMEM(str1, ptr1, len1);
2580 RSTRING_GETMEM(str2, ptr2, len2);
2581 int enc1 = rb_enc_get_index(str1);
2582 int enc2 = rb_enc_get_index(str2);
2583
2584 if (enc1 < 0) {
2585 return Qundef;
2586 }
2587 else if (enc2 < 0) {
2588 return Qundef;
2589 }
2590 else if (enc1 != enc2) {
2591 return Qundef;
2592 }
2593 else if (len1 > LONG_MAX - len2) {
2594 return Qundef;
2595 }
2596 else {
2597 return rb_str_plus(str1, str2);
2598 }
2599
2600}
2601
2602/*
2603 * call-seq:
2604 * self * n -> new_string
2605 *
2606 * Returns a new string containing +n+ copies of +self+:
2607 *
2608 * 'Ho!' * 3 # => "Ho!Ho!Ho!"
2609 * 'No!' * 0 # => ""
2610 *
2611 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2612 */
2613
2614VALUE
2616{
2617 VALUE str2;
2618 long n, len;
2619 char *ptr2;
2620 int termlen;
2621
2622 if (times == INT2FIX(1)) {
2623 return str_duplicate(rb_cString, str);
2624 }
2625 if (times == INT2FIX(0)) {
2626 str2 = str_alloc_embed(rb_cString, 0);
2627 rb_enc_copy(str2, str);
2628 return str2;
2629 }
2630 len = NUM2LONG(times);
2631 if (len < 0) {
2632 rb_raise(rb_eArgError, "negative argument");
2633 }
2634 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2635 if (STR_EMBEDDABLE_P(len, 1)) {
2636 str2 = str_alloc_embed(rb_cString, len + 1);
2637 memset(RSTRING_PTR(str2), 0, len + 1);
2638 }
2639 else {
2640 str2 = str_alloc_heap(rb_cString);
2641 RSTRING(str2)->as.heap.aux.capa = len;
2642 RSTRING(str2)->as.heap.ptr = ZALLOC_N(char, (size_t)len + 1);
2643 }
2644 STR_SET_LEN(str2, len);
2645 rb_enc_copy(str2, str);
2646 return str2;
2647 }
2648 if (len && LONG_MAX/len < RSTRING_LEN(str)) {
2649 rb_raise(rb_eArgError, "argument too big");
2650 }
2651
2652 len *= RSTRING_LEN(str);
2653 termlen = TERM_LEN(str);
2654 str2 = str_enc_new(rb_cString, 0, len, STR_ENC_GET(str));
2655 ptr2 = RSTRING_PTR(str2);
2656 if (len) {
2657 n = RSTRING_LEN(str);
2658 memcpy(ptr2, RSTRING_PTR(str), n);
2659 while (n <= len/2) {
2660 memcpy(ptr2 + n, ptr2, n);
2661 n *= 2;
2662 }
2663 memcpy(ptr2 + n, ptr2, len-n);
2664 }
2665 STR_SET_LEN(str2, len);
2666 TERM_FILL(&ptr2[len], termlen);
2667 rb_enc_cr_str_copy_for_substr(str2, str);
2668
2669 return str2;
2670}
2671
2672/*
2673 * call-seq:
2674 * self % object -> new_string
2675 *
2676 * Returns the result of formatting +object+ into the format specifications
2677 * contained in +self+
2678 * (see {Format Specifications}[rdoc-ref:language/format_specifications.rdoc]):
2679 *
2680 * '%05d' % 123 # => "00123"
2681 *
2682 * If +self+ contains multiple format specifications,
2683 * +object+ must be an array or hash containing the objects to be formatted:
2684 *
2685 * '%-5s: %016x' % [ 'ID', self.object_id ] # => "ID : 00002b054ec93168"
2686 * 'foo = %{foo}' % {foo: 'bar'} # => "foo = bar"
2687 * 'foo = %{foo}, baz = %{baz}' % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
2688 *
2689 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2690 */
2691
2692static VALUE
2693rb_str_format_m(VALUE str, VALUE arg)
2694{
2695 VALUE tmp = rb_check_array_type(arg);
2696
2697 if (!NIL_P(tmp)) {
2698 VALUE result = rb_str_format(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str);
2699 RB_GC_GUARD(tmp);
2700 return result;
2701 }
2702 return rb_str_format(1, &arg, str);
2703}
2704
2705static inline void
2706rb_check_lockedtmp(VALUE str)
2707{
2708 if (FL_TEST(str, STR_TMPLOCK)) {
2709 rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked");
2710 }
2711}
2712
2713// If none of these flags are set, we know we have an modifiable string.
2714// If any is set, we need to do more detailed checks.
2715#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2716static inline void
2717str_modifiable(VALUE str)
2718{
2719 RUBY_ASSERT(ruby_thread_has_gvl_p());
2720
2721 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2722 if (CHILLED_STRING_P(str)) {
2723 CHILLED_STRING_MUTATED(str);
2724 }
2725 rb_check_lockedtmp(str);
2726 rb_check_frozen(str);
2727 }
2728}
2729
2730static inline int
2731str_dependent_p(VALUE str)
2732{
2733 if (STR_EMBED_P(str) || !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2734 return FALSE;
2735 }
2736 else {
2737 return TRUE;
2738 }
2739}
2740
2741// If none of these flags are set, we know we have an independent string.
2742// If any is set, we need to do more detailed checks.
2743#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2744static inline int
2745str_independent(VALUE str)
2746{
2747 RUBY_ASSERT(ruby_thread_has_gvl_p());
2748
2749 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2750 str_modifiable(str);
2751 return !str_dependent_p(str);
2752 }
2753 return TRUE;
2754}
2755
2756static void
2757str_make_independent_expand(VALUE str, long len, long expand, const int termlen)
2758{
2759 RUBY_ASSERT(ruby_thread_has_gvl_p());
2760
2761 char *ptr;
2762 char *oldptr;
2763 long capa = len + expand;
2764
2765 if (len > capa) len = capa;
2766
2767 if (!STR_EMBED_P(str) && str_embed_capa(str) >= capa + termlen) {
2768 ptr = RSTRING(str)->as.heap.ptr;
2769 STR_SET_EMBED(str);
2770 memcpy(RSTRING(str)->as.embed.ary, ptr, len);
2771 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
2772 STR_SET_LEN(str, len);
2773 return;
2774 }
2775
2776 ptr = ALLOC_N(char, (size_t)capa + termlen);
2777 oldptr = RSTRING_PTR(str);
2778 if (oldptr) {
2779 memcpy(ptr, oldptr, len);
2780 }
2781 if (FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2782 SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
2783 }
2784 STR_SET_NOEMBED(str);
2785 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2786 TERM_FILL(ptr + len, termlen);
2787 RSTRING(str)->as.heap.ptr = ptr;
2788 STR_SET_LEN(str, len);
2789 RSTRING(str)->as.heap.aux.capa = capa;
2790}
2791
2792void
2793rb_str_modify(VALUE str)
2794{
2795 if (!str_independent(str))
2796 str_make_independent(str);
2798}
2799
2800void
2802{
2803 RUBY_ASSERT(ruby_thread_has_gvl_p());
2804
2805 int termlen = TERM_LEN(str);
2806 long len = RSTRING_LEN(str);
2807
2808 if (expand < 0) {
2809 rb_raise(rb_eArgError, "negative expanding string size");
2810 }
2811 if (expand >= LONG_MAX - len) {
2812 rb_raise(rb_eArgError, "string size too big");
2813 }
2814
2815 if (!str_independent(str)) {
2816 str_make_independent_expand(str, len, expand, termlen);
2817 }
2818 else if (expand > 0) {
2819 RESIZE_CAPA_TERM(str, len + expand, termlen);
2820 }
2822}
2823
2824/* As rb_str_modify(), but don't clear coderange */
2825static void
2826str_modify_keep_cr(VALUE str)
2827{
2828 if (!str_independent(str))
2829 str_make_independent(str);
2831 /* Force re-scan later */
2833}
2834
2835static inline void
2836str_discard(VALUE str)
2837{
2838 str_modifiable(str);
2839 if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2840 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2841 RSTRING(str)->as.heap.ptr = 0;
2842 STR_SET_LEN(str, 0);
2843 }
2844}
2845
2846void
2848{
2849 int encindex = rb_enc_get_index(str);
2850
2851 if (RB_UNLIKELY(encindex == -1)) {
2852 rb_raise(rb_eTypeError, "not encoding capable object");
2853 }
2854
2855 if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
2856 return;
2857 }
2858
2859 rb_encoding *enc = rb_enc_from_index(encindex);
2860 if (!rb_enc_asciicompat(enc)) {
2861 rb_raise(rb_eEncCompatError, "ASCII incompatible encoding: %s", rb_enc_name(enc));
2862 }
2863}
2864
2865VALUE
2867{
2868 RUBY_ASSERT(ruby_thread_has_gvl_p());
2869
2870 VALUE s = *ptr;
2871 if (!RB_TYPE_P(s, T_STRING)) {
2872 s = rb_str_to_str(s);
2873 *ptr = s;
2874 }
2875 return s;
2876}
2877
2878char *
2880{
2881 VALUE str = rb_string_value(ptr);
2882 return RSTRING_PTR(str);
2883}
2884
2885static const char *
2886str_null_char(const char *s, long len, const int minlen, rb_encoding *enc)
2887{
2888 const char *e = s + len;
2889
2890 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2891 if (zero_filled(s, minlen)) return s;
2892 }
2893 return 0;
2894}
2895
2896static char *
2897str_fill_term(VALUE str, char *s, long len, int termlen)
2898{
2899 /* This function assumes that (capa + termlen) bytes of memory
2900 * is allocated, like many other functions in this file.
2901 */
2902 if (str_dependent_p(str)) {
2903 if (!zero_filled(s + len, termlen))
2904 str_make_independent_expand(str, len, 0L, termlen);
2905 }
2906 else {
2907 TERM_FILL(s + len, termlen);
2908 return s;
2909 }
2910 return RSTRING_PTR(str);
2911}
2912
2913void
2914rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen)
2915{
2916 long capa = str_capacity(str, oldtermlen) + oldtermlen;
2917 long len = RSTRING_LEN(str);
2918
2919 RUBY_ASSERT(capa >= len);
2920 if (capa - len < termlen) {
2921 rb_check_lockedtmp(str);
2922 str_make_independent_expand(str, len, 0L, termlen);
2923 }
2924 else if (str_dependent_p(str)) {
2925 if (termlen > oldtermlen)
2926 str_make_independent_expand(str, len, 0L, termlen);
2927 }
2928 else {
2929 if (!STR_EMBED_P(str)) {
2930 /* modify capa instead of realloc */
2931 RUBY_ASSERT(!FL_TEST((str), STR_SHARED));
2932 RSTRING(str)->as.heap.aux.capa = capa - termlen;
2933 }
2934 if (termlen > oldtermlen) {
2935 TERM_FILL(RSTRING_PTR(str) + len, termlen);
2936 }
2937 }
2938
2939 return;
2940}
2941
2942static char *
2943str_null_check(VALUE str, int *w)
2944{
2945 char *s = RSTRING_PTR(str);
2946 long len = RSTRING_LEN(str);
2947 int minlen = 1;
2948
2949 if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
2950 rb_encoding *enc = rb_str_enc_get(str);
2951 minlen = rb_enc_mbminlen(enc);
2952
2953 if (minlen > 1) {
2954 *w = 1;
2955 if (str_null_char(s, len, minlen, enc)) {
2956 return NULL;
2957 }
2958 return str_fill_term(str, s, len, minlen);
2959 }
2960 }
2961
2962 *w = 0;
2963 if (!s || memchr(s, 0, len)) {
2964 return NULL;
2965 }
2966 if (s[len]) {
2967 s = str_fill_term(str, s, len, minlen);
2968 }
2969 return s;
2970}
2971
2972static char *str_to_cstr(VALUE str);
2973
2974const char *
2975rb_str_null_check(VALUE str)
2976{
2978
2979 const char *s;
2980 long len;
2981 RSTRING_GETMEM(str, s, len);
2982
2983 if (RB_LIKELY(rb_str_enc_fastpath(str))) {
2984 if (!s || memchr(s, 0, len)) {
2985 rb_raise(rb_eArgError, "string contains null byte");
2986 }
2987 }
2988 else {
2989 str_to_cstr(str);
2990 }
2991
2992 return s;
2993}
2994
2995char *
2996rb_str_to_cstr(VALUE str)
2997{
2998 int w;
2999 return str_null_check(str, &w);
3000}
3001
3002char *
3004{
3005 VALUE str = rb_string_value(ptr);
3006 return str_to_cstr(str);
3007}
3008
3009static char *
3010str_to_cstr(VALUE str)
3011{
3012 int w;
3013 char *s = str_null_check(str, &w);
3014 if (!s) {
3015 if (w) {
3016 rb_raise(rb_eArgError, "string contains null char");
3017 }
3018 rb_raise(rb_eArgError, "string contains null byte");
3019 }
3020 return s;
3021}
3022
3023char *
3024rb_str_fill_terminator(VALUE str, const int newminlen)
3025{
3026 char *s = RSTRING_PTR(str);
3027 long len = RSTRING_LEN(str);
3028 return str_fill_term(str, s, len, newminlen);
3029}
3030
3031VALUE
3033{
3034 str = rb_check_convert_type_with_id(str, T_STRING, "String", idTo_str);
3035 return str;
3036}
3037
3038/*
3039 * call-seq:
3040 * String.try_convert(object) -> object, new_string, or nil
3041 *
3042 * Attempts to convert the given +object+ to a string.
3043 *
3044 * If +object+ is already a string, returns +object+, unmodified.
3045 *
3046 * Otherwise if +object+ responds to <tt>:to_str</tt>,
3047 * calls <tt>object.to_str</tt> and returns the result.
3048 *
3049 * Returns +nil+ if +object+ does not respond to <tt>:to_str</tt>.
3050 *
3051 * Raises an exception unless <tt>object.to_str</tt> returns a string.
3052 */
3053static VALUE
3054rb_str_s_try_convert(VALUE dummy, VALUE str)
3055{
3056 return rb_check_string_type(str);
3057}
3058
3059static char*
3060str_nth_len(const char *p, const char *e, long *nthp, rb_encoding *enc)
3061{
3062 long nth = *nthp;
3063 if (rb_enc_mbmaxlen(enc) == 1) {
3064 p += nth;
3065 }
3066 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
3067 p += nth * rb_enc_mbmaxlen(enc);
3068 }
3069 else if (rb_enc_asciicompat(enc)) {
3070 const char *p2, *e2;
3071 int n;
3072
3073 while (p < e && 0 < nth) {
3074 e2 = p + nth;
3075 if (e < e2) {
3076 *nthp = nth;
3077 return (char *)e;
3078 }
3079 p2 = search_nonascii(p, e2);
3080 if (!p2) {
3081 nth -= e2 - p;
3082 *nthp = nth;
3083 return (char *)e2;
3084 }
3085 nth -= p2 - p;
3086 p = p2;
3087 n = rb_enc_mbclen(p, e, enc);
3088 p += n;
3089 nth--;
3090 }
3091 *nthp = nth;
3092 if (nth != 0) {
3093 return (char *)e;
3094 }
3095 return (char *)p;
3096 }
3097 else {
3098 while (p < e && nth--) {
3099 p += rb_enc_mbclen(p, e, enc);
3100 }
3101 }
3102 if (p > e) p = e;
3103 *nthp = nth;
3104 return (char*)p;
3105}
3106
3107char*
3108rb_enc_nth(const char *p, const char *e, long nth, rb_encoding *enc)
3109{
3110 return str_nth_len(p, e, &nth, enc);
3111}
3112
3113static char*
3114str_nth(const char *p, const char *e, long nth, rb_encoding *enc, int singlebyte)
3115{
3116 if (singlebyte)
3117 p += nth;
3118 else {
3119 p = str_nth_len(p, e, &nth, enc);
3120 }
3121 if (!p) return 0;
3122 if (p > e) p = e;
3123 return (char *)p;
3124}
3125
3126/* char offset to byte offset */
3127static long
3128str_offset(const char *p, const char *e, long nth, rb_encoding *enc, int singlebyte)
3129{
3130 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3131 if (!pp) return e - p;
3132 return pp - p;
3133}
3134
3135long
3136rb_str_offset(VALUE str, long pos)
3137{
3138 return str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
3139 STR_ENC_GET(str), single_byte_optimizable(str));
3140}
3141
3142#ifdef NONASCII_MASK
3143static char *
3144str_utf8_nth(const char *p, const char *e, long *nthp)
3145{
3146 long nth = *nthp;
3147 if ((int)SIZEOF_VOIDP * 2 < e - p && (int)SIZEOF_VOIDP * 2 < nth) {
3148 const uintptr_t *s, *t;
3149 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3150 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3151 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
3152 while (p < (const char *)s) {
3153 if (is_utf8_lead_byte(*p)) nth--;
3154 p++;
3155 }
3156 do {
3157 nth -= count_utf8_lead_bytes_with_word(s);
3158 s++;
3159 } while (s < t && (int)SIZEOF_VOIDP <= nth);
3160 p = (char *)s;
3161 }
3162 while (p < e) {
3163 if (is_utf8_lead_byte(*p)) {
3164 if (nth == 0) break;
3165 nth--;
3166 }
3167 p++;
3168 }
3169 *nthp = nth;
3170 return (char *)p;
3171}
3172
3173static long
3174str_utf8_offset(const char *p, const char *e, long nth)
3175{
3176 const char *pp = str_utf8_nth(p, e, &nth);
3177 return pp - p;
3178}
3179#endif
3180
3181/* byte offset to char offset */
3182long
3183rb_str_sublen(VALUE str, long pos)
3184{
3185 if (single_byte_optimizable(str) || pos < 0)
3186 return pos;
3187 else {
3188 const char *p = RSTRING_PTR(str);
3189 return enc_strlen(p, p + pos, STR_ENC_GET(str), ENC_CODERANGE(str));
3190 }
3191}
3192
3193static VALUE
3194str_subseq(VALUE str, long beg, long len)
3195{
3196 VALUE str2;
3197
3198 RUBY_ASSERT(beg >= 0);
3199 RUBY_ASSERT(len >= 0);
3200 RUBY_ASSERT(beg+len <= RSTRING_LEN(str));
3201
3202 const int termlen = TERM_LEN(str);
3203 if (!SHARABLE_SUBSTRING_P(str, beg, len)) {
3204 str2 = rb_enc_str_new(RSTRING_PTR(str) + beg, len, rb_str_enc_get(str));
3205 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
3207 }
3208 RB_GC_GUARD(str);
3209 return str2;
3210 }
3211
3212 /* Sharing allocates a shared root as well unless str can be one itself, so
3213 * a copy is worth a larger slot only when it saves that second object. */
3214 const bool root_available = STR_SHARED_P(str) ||
3215 RB_FL_TEST_RAW(str, FL_FREEZE | STR_CHILLED) == FL_FREEZE;
3216 const size_t max_embed_size = root_available ?
3217 rb_gc_size_slot_size(sizeof(struct RString)) : STR_COPY_MAX_EMBED_SIZE;
3218 const size_t embed_size = rb_str_embed_size(len, termlen);
3219
3220 if (embed_size <= max_embed_size && rb_gc_size_allocatable_p(embed_size)) {
3221 str2 = str_alloc_embed(rb_cString, len + termlen);
3222 char *ptr2 = RSTRING(str2)->as.embed.ary;
3223 memcpy(ptr2, RSTRING_PTR(str) + beg, len);
3224 TERM_FILL(ptr2 + len, termlen);
3225
3226 STR_SET_LEN(str2, len);
3227 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
3229 }
3230
3231 RB_GC_GUARD(str);
3232 }
3233 else {
3234 str2 = str_alloc_heap(rb_cString);
3235 str_replace_shared(str2, str);
3236 RUBY_ASSERT(!STR_EMBED_P(str2));
3237 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
3238 ENC_CODERANGE_CLEAR(str2);
3239 }
3240
3241 RSTRING(str2)->as.heap.ptr += beg;
3242 if (RSTRING_LEN(str2) > len) {
3243 STR_SET_LEN(str2, len);
3244 }
3245 }
3246
3247 return str2;
3248}
3249
3250VALUE
3251rb_str_subseq(VALUE str, long beg, long len)
3252{
3253 VALUE str2 = str_subseq(str, beg, len);
3254 rb_enc_cr_str_copy_for_substr(str2, str);
3255 return str2;
3256}
3257
3258char *
3259rb_str_subpos(VALUE str, long beg, long *lenp)
3260{
3261 long len = *lenp;
3262 long slen = -1L;
3263 const long blen = RSTRING_LEN(str);
3264 rb_encoding *enc = STR_ENC_GET(str);
3265 const char *p, *s = RSTRING_PTR(str), *e = s + blen;
3266
3267 if (len < 0) return 0;
3268 if (beg < 0 && -beg < 0) return 0;
3269 if (!blen) {
3270 len = 0;
3271 }
3272 if (single_byte_optimizable(str)) {
3273 if (beg > blen) return 0;
3274 if (beg < 0) {
3275 beg += blen;
3276 if (beg < 0) return 0;
3277 }
3278 if (len > blen - beg)
3279 len = blen - beg;
3280 if (len < 0) return 0;
3281 p = s + beg;
3282 goto end;
3283 }
3284 if (beg < 0) {
3285 if (len > -beg) len = -beg;
3286 if ((ENC_CODERANGE(str) == ENC_CODERANGE_VALID) &&
3287 (-beg * rb_enc_mbmaxlen(enc) < blen / 8)) {
3288 beg = -beg;
3289 while (beg-- > len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3290 p = e;
3291 if (!p) return 0;
3292 while (len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3293 if (!p) return 0;
3294 len = e - p;
3295 goto end;
3296 }
3297 else {
3298 slen = str_strlen(str, enc);
3299 beg += slen;
3300 if (beg < 0) return 0;
3301 p = s + beg;
3302 if (len == 0) goto end;
3303 }
3304 }
3305 else if (beg > 0 && beg > blen) {
3306 return 0;
3307 }
3308 if (len == 0) {
3309 if (beg > str_strlen(str, enc)) return 0; /* str's enc */
3310 p = s + beg;
3311 }
3312#ifdef NONASCII_MASK
3313 else if (ENC_CODERANGE(str) == ENC_CODERANGE_VALID &&
3314 enc == rb_utf8_encoding()) {
3315 p = str_utf8_nth(s, e, &beg);
3316 if (beg > 0) return 0;
3317 len = str_utf8_offset(p, e, len);
3318 }
3319#endif
3320 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
3321 int char_sz = rb_enc_mbmaxlen(enc);
3322
3323 p = s + beg * char_sz;
3324 if (p > e) {
3325 return 0;
3326 }
3327 else if (len * char_sz > e - p)
3328 len = e - p;
3329 else
3330 len *= char_sz;
3331 }
3332 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3333 if (beg > 0) return 0;
3334 len = 0;
3335 }
3336 else {
3337 len = str_offset(p, e, len, enc, 0);
3338 }
3339 end:
3340 *lenp = len;
3341 RB_GC_GUARD(str);
3342 return (char *)p;
3343}
3344
3345static VALUE str_substr(VALUE str, long beg, long len, int empty);
3346
3347VALUE
3348rb_str_substr(VALUE str, long beg, long len)
3349{
3350 return str_substr(str, beg, len, TRUE);
3351}
3352
3353VALUE
3354rb_str_substr_two_fixnums(VALUE str, VALUE beg, VALUE len, int empty)
3355{
3356 return str_substr(str, NUM2LONG(beg), NUM2LONG(len), empty);
3357}
3358
3359static VALUE
3360str_substr(VALUE str, long beg, long len, int empty)
3361{
3362 const char *p = rb_str_subpos(str, beg, &len);
3363
3364 if (!p) return Qnil;
3365 if (!len && !empty) return Qnil;
3366
3367 beg = p - RSTRING_PTR(str);
3368
3369 VALUE str2 = str_subseq(str, beg, len);
3370 rb_enc_cr_str_copy_for_substr(str2, str);
3371 return str2;
3372}
3373
3374/* :nodoc: */
3375VALUE
3377{
3378 if (CHILLED_STRING_P(str)) {
3379 FL_UNSET_RAW(str, STR_CHILLED);
3380 }
3381
3382 if (OBJ_FROZEN(str)) return str;
3383 rb_str_resize(str, RSTRING_LEN(str));
3384 return rb_obj_freeze(str);
3385}
3386
3387/*
3388 * call-seq:
3389 * +string -> new_string or self
3390 *
3391 * Returns +self+ if +self+ is not frozen and can be mutated
3392 * without warning issuance.
3393 *
3394 * Otherwise returns <tt>self.dup</tt>, which is not frozen.
3395 *
3396 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
3397 */
3398static VALUE
3399str_uplus(VALUE str)
3400{
3401 if (OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3402 return rb_str_dup(str);
3403 }
3404 else {
3405 return str;
3406 }
3407}
3408
3409/*
3410 * call-seq:
3411 * -self -> frozen_string
3412 *
3413 * Returns a frozen string equal to +self+.
3414 *
3415 * The returned string is +self+ if and only if all of the following are true:
3416 *
3417 * - +self+ is already frozen.
3418 * - +self+ is an instance of \String (rather than of a subclass of \String)
3419 * - +self+ has no instance variables set on it.
3420 *
3421 * Otherwise, the returned string is a frozen copy of +self+.
3422 *
3423 * Returning +self+, when possible, saves duplicating +self+;
3424 * see {Data deduplication}[https://en.wikipedia.org/wiki/Data_deduplication].
3425 *
3426 * It may also save duplicating other, already-existing, strings:
3427 *
3428 * s0 = 'foo'
3429 * s1 = 'foo'
3430 * s0.object_id == s1.object_id # => false
3431 * (-s0).object_id == (-s1).object_id # => true
3432 *
3433 * Note that method #-@ is convenient for defining a constant:
3434 *
3435 * FileName = -'config/database.yml'
3436 *
3437 * While its alias #dedup is better suited for chaining:
3438 *
3439 * 'foo'.dedup.gsub!('o')
3440 *
3441 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
3442 */
3443static VALUE
3444str_uminus(VALUE str)
3445{
3446 if (!BARE_STRING_P(str) && !rb_obj_frozen_p(str)) {
3447 str = rb_str_dup(str);
3448 }
3449 return rb_fstring(str);
3450}
3451
3452RUBY_ALIAS_FUNCTION(rb_str_dup_frozen(VALUE str), rb_str_new_frozen, (str))
3453#define rb_str_dup_frozen rb_str_new_frozen
3454
3455VALUE
3457{
3458 rb_check_frozen(str);
3459 if (FL_TEST(str, STR_TMPLOCK)) {
3460 rb_raise(rb_eRuntimeError, "temporal locking already locked string");
3461 }
3462 FL_SET(str, STR_TMPLOCK);
3463 return str;
3464}
3465
3466VALUE
3468{
3469 rb_check_frozen(str);
3470 if (!FL_TEST(str, STR_TMPLOCK)) {
3471 rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string");
3472 }
3473 FL_UNSET(str, STR_TMPLOCK);
3474 return str;
3475}
3476
3477VALUE
3478rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg)
3479{
3480 rb_str_locktmp(str);
3481 return rb_ensure(func, arg, rb_str_unlocktmp, str);
3482}
3483
3484void
3486{
3487 RUBY_ASSERT(ruby_thread_has_gvl_p());
3488
3489 long capa;
3490 const int termlen = TERM_LEN(str);
3491
3492 str_modifiable(str);
3493 if (STR_SHARED_P(str)) {
3494 rb_raise(rb_eRuntimeError, "can't set length of shared string");
3495 }
3496 if (len > (capa = (long)str_capacity(str, termlen)) || len < 0) {
3497 rb_bug("probable buffer overflow: %ld for %ld", len, capa);
3498 }
3499
3500 int cr = ENC_CODERANGE(str);
3501 if (len == 0) {
3502 /* Empty string does not contain non-ASCII */
3504 }
3505 else if (cr == ENC_CODERANGE_UNKNOWN) {
3506 /* Leave unknown. */
3507 }
3508 else if (len > RSTRING_LEN(str)) {
3509 if (ENC_CODERANGE_CLEAN_P(cr)) {
3510 /* Update the coderange regarding the extended part. */
3511 const char *const prev_end = RSTRING_END(str);
3512 const char *const new_end = RSTRING_PTR(str) + len;
3513 rb_encoding *enc = rb_enc_get(str);
3514 rb_str_coderange_scan_restartable(prev_end, new_end, enc, &cr);
3515 ENC_CODERANGE_SET(str, cr);
3516 }
3517 else if (cr == ENC_CODERANGE_BROKEN) {
3518 /* May be valid now, by appended part. */
3520 }
3521 }
3522 else if (len < RSTRING_LEN(str)) {
3523 if (cr != ENC_CODERANGE_7BIT) {
3524 /* ASCII-only string is keeping after truncated. Valid
3525 * and broken may be invalid or valid, leave unknown. */
3527 }
3528 }
3529
3530 STR_SET_LEN(str, len);
3531 TERM_FILL(&RSTRING_PTR(str)[len], termlen);
3532}
3533
3534VALUE
3535rb_str_resize(VALUE str, long len)
3536{
3537 if (len < 0) {
3538 rb_raise(rb_eArgError, "negative string size (or size too big)");
3539 }
3540
3541 int independent = str_independent(str);
3542 long slen = RSTRING_LEN(str);
3543 const int termlen = TERM_LEN(str);
3544
3545 if (slen > len || (termlen != 1 && slen < len)) {
3547 }
3548
3549 {
3550 long capa;
3551 if (STR_EMBED_P(str)) {
3552 if (len == slen) return str;
3553 if (str_embed_capa(str) >= len + termlen) {
3554 STR_SET_LEN(str, len);
3555 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3556 return str;
3557 }
3558 str_make_independent_expand(str, slen, len - slen, termlen);
3559 }
3560 else if (str_embed_capa(str) >= len + termlen) {
3561 capa = RSTRING(str)->as.heap.aux.capa;
3562 char *ptr = STR_HEAP_PTR(str);
3563 STR_SET_EMBED(str);
3564 if (slen > len) slen = len;
3565 if (slen > 0) MEMCPY(RSTRING(str)->as.embed.ary, ptr, char, slen);
3566 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3567 STR_SET_LEN(str, len);
3568 if (independent) {
3569 SIZED_FREE_N(ptr, capa + termlen);
3570 }
3571 return str;
3572 }
3573 else if (!independent) {
3574 if (len == slen) return str;
3575 str_make_independent_expand(str, slen, len - slen, termlen);
3576 }
3577 else if ((capa = RSTRING(str)->as.heap.aux.capa) < len ||
3578 (capa - len) > (len < 1024 ? len : 1024)) {
3579 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
3580 (size_t)len + termlen, STR_HEAP_SIZE(str));
3581 RSTRING(str)->as.heap.aux.capa = len;
3582 }
3583 else if (len == slen) return str;
3584 STR_SET_LEN(str, len);
3585 TERM_FILL(RSTRING(str)->as.heap.ptr + len, termlen); /* sentinel */
3586 }
3587 return str;
3588}
3589
3590static void
3591str_ensure_available_capa(VALUE str, long len)
3592{
3593 str_modify_keep_cr(str);
3594
3595 const int termlen = TERM_LEN(str);
3596 long olen = RSTRING_LEN(str);
3597
3598 if (RB_UNLIKELY(olen > LONG_MAX - len)) {
3599 rb_raise(rb_eArgError, "string sizes too big");
3600 }
3601
3602 long total = olen + len;
3603 long capa = str_capacity(str, termlen);
3604
3605 if (capa < total) {
3606 if (total >= LONG_MAX / 2) {
3607 capa = total;
3608 }
3609 while (total > capa) {
3610 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3611 }
3612 RESIZE_CAPA_TERM(str, capa, termlen);
3613 }
3614}
3615
3616static VALUE
3617str_buf_cat4(VALUE str, const char *ptr, long len, bool keep_cr)
3618{
3619 if (keep_cr) {
3620 str_modify_keep_cr(str);
3621 }
3622 else {
3623 rb_str_modify(str);
3624 }
3625 if (len == 0) return 0;
3626
3627 long total, olen, off = -1;
3628 char *sptr;
3629 const int termlen = TERM_LEN(str);
3630
3631 RSTRING_GETMEM(str, sptr, olen);
3632 if (ptr >= sptr && ptr <= sptr + olen) {
3633 off = ptr - sptr;
3634 }
3635
3636 long capa = str_capacity(str, termlen);
3637
3638 if (olen > LONG_MAX - len) {
3639 rb_raise(rb_eArgError, "string sizes too big");
3640 }
3641 total = olen + len;
3642 if (capa < total) {
3643 if (total >= LONG_MAX / 2) {
3644 capa = total;
3645 }
3646 while (total > capa) {
3647 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3648 }
3649 RESIZE_CAPA_TERM(str, capa, termlen);
3650 sptr = RSTRING_PTR(str);
3651 }
3652 if (off != -1) {
3653 ptr = sptr + off;
3654 }
3655 memcpy(sptr + olen, ptr, len);
3656 STR_SET_LEN(str, total);
3657 TERM_FILL(sptr + total, termlen); /* sentinel */
3658
3659 return str;
3660}
3661
3662#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3663#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3664
3665VALUE
3666rb_str_cat(VALUE str, const char *ptr, long len)
3667{
3668 if (len == 0) return str;
3669 if (len < 0) {
3670 rb_raise(rb_eArgError, "negative string size (or size too big)");
3671 }
3672 return str_buf_cat(str, ptr, len);
3673}
3674
3675VALUE
3676rb_str_cat_cstr(VALUE str, const char *ptr)
3677{
3678 must_not_null(ptr);
3679 return rb_str_buf_cat(str, ptr, strlen(ptr));
3680}
3681
3682static void
3683rb_str_buf_cat_byte(VALUE str, unsigned char byte)
3684{
3685 RUBY_ASSERT(RB_ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT || RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII);
3686
3687 // We can't write directly to shared strings without impacting others, so we must make the string independent.
3688 if (UNLIKELY(!str_independent(str))) {
3689 str_make_independent(str);
3690 }
3691
3692 long string_length = -1;
3693 const int null_terminator_length = 1;
3694 char *sptr;
3695 RSTRING_GETMEM(str, sptr, string_length);
3696
3697 // Ensure the resulting string wouldn't be too long.
3698 if (UNLIKELY(string_length > LONG_MAX - 1)) {
3699 rb_raise(rb_eArgError, "string sizes too big");
3700 }
3701
3702 long string_capacity = str_capacity(str, null_terminator_length);
3703
3704 // Get the code range before any modifications since those might clear the code range.
3705 int cr = ENC_CODERANGE(str);
3706
3707 // Check if the string has spare string_capacity to write the new byte.
3708 if (LIKELY(string_capacity >= string_length + 1)) {
3709 // In fast path we can write the new byte and note the string's new length.
3710 sptr[string_length] = byte;
3711 STR_SET_LEN(str, string_length + 1);
3712 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3713 }
3714 else {
3715 // If there's not enough string_capacity, make a call into the general string concatenation function.
3716 str_buf_cat(str, (char *)&byte, 1);
3717 }
3718
3719 // If the code range is already known, we can derive the resulting code range cheaply by looking at the byte we
3720 // just appended. If the code range is unknown, but the string was empty, then we can also derive the code range
3721 // by looking at the byte we just appended. Otherwise, we'd have to scan the bytes to determine the code range so
3722 // we leave it as unknown. It cannot be broken for binary strings so we don't need to handle that option.
3723 if (cr == ENC_CODERANGE_7BIT || string_length == 0) {
3724 if (ISASCII(byte)) {
3726 }
3727 else {
3729
3730 // Promote a US-ASCII string to ASCII-8BIT when a non-ASCII byte is appended.
3731 if (UNLIKELY(RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)) {
3732 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3733 }
3734 }
3735 }
3736}
3737
3738RUBY_ALIAS_FUNCTION(rb_str_buf_cat(VALUE str, const char *ptr, long len), rb_str_cat, (str, ptr, len))
3739RUBY_ALIAS_FUNCTION(rb_str_buf_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3740RUBY_ALIAS_FUNCTION(rb_str_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3741
3742static VALUE
3743rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, long len,
3744 int ptr_encindex, int ptr_cr, int *ptr_cr_ret)
3745{
3746 int str_encindex = ENCODING_GET(str);
3747 int res_encindex;
3748 int str_cr, res_cr;
3749 rb_encoding *str_enc, *ptr_enc;
3750
3751 str_cr = RSTRING_LEN(str) ? ENC_CODERANGE(str) : ENC_CODERANGE_7BIT;
3752
3753 if (str_encindex == ptr_encindex) {
3754 if (str_cr != ENC_CODERANGE_UNKNOWN && ptr_cr == ENC_CODERANGE_UNKNOWN) {
3755 ptr_cr = coderange_scan(ptr, len, rb_enc_from_index(ptr_encindex));
3756 }
3757 }
3758 else {
3759 str_enc = rb_enc_from_index(str_encindex);
3760 ptr_enc = rb_enc_from_index(ptr_encindex);
3761 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3762 if (len == 0)
3763 return str;
3764 if (RSTRING_LEN(str) == 0) {
3765 rb_str_buf_cat(str, ptr, len);
3766 ENCODING_CODERANGE_SET(str, ptr_encindex, ptr_cr);
3767 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3768 return str;
3769 }
3770 goto incompatible;
3771 }
3772 if (ptr_cr == ENC_CODERANGE_UNKNOWN) {
3773 ptr_cr = coderange_scan(ptr, len, ptr_enc);
3774 }
3775 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3776 if (ENCODING_IS_ASCII8BIT(str) || ptr_cr != ENC_CODERANGE_7BIT) {
3777 str_cr = rb_enc_str_coderange(str);
3778 }
3779 }
3780 }
3781 if (ptr_cr_ret)
3782 *ptr_cr_ret = ptr_cr;
3783
3784 if (str_encindex != ptr_encindex &&
3785 str_cr != ENC_CODERANGE_7BIT &&
3786 ptr_cr != ENC_CODERANGE_7BIT) {
3787 str_enc = rb_enc_from_index(str_encindex);
3788 ptr_enc = rb_enc_from_index(ptr_encindex);
3789 goto incompatible;
3790 }
3791
3792 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3793 res_encindex = str_encindex;
3794 res_cr = ENC_CODERANGE_UNKNOWN;
3795 }
3796 else if (str_cr == ENC_CODERANGE_7BIT) {
3797 if (ptr_cr == ENC_CODERANGE_7BIT) {
3798 res_encindex = str_encindex;
3799 res_cr = ENC_CODERANGE_7BIT;
3800 }
3801 else {
3802 res_encindex = ptr_encindex;
3803 res_cr = ptr_cr;
3804 }
3805 }
3806 else if (str_cr == ENC_CODERANGE_VALID) {
3807 res_encindex = str_encindex;
3808 if (ENC_CODERANGE_CLEAN_P(ptr_cr))
3809 res_cr = str_cr;
3810 else
3811 res_cr = ptr_cr;
3812 }
3813 else { /* str_cr == ENC_CODERANGE_BROKEN */
3814 res_encindex = str_encindex;
3815 res_cr = str_cr;
3816 if (0 < len) res_cr = ENC_CODERANGE_UNKNOWN;
3817 }
3818
3819 if (len < 0) {
3820 rb_raise(rb_eArgError, "negative string size (or size too big)");
3821 }
3822 str_buf_cat(str, ptr, len);
3823 ENCODING_CODERANGE_SET(str, res_encindex, res_cr);
3824 return str;
3825
3826 incompatible:
3827 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
3828 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3830}
3831
3832VALUE
3833rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *ptr_enc)
3834{
3835 return rb_enc_cr_str_buf_cat(str, ptr, len,
3836 rb_enc_to_index(ptr_enc), ENC_CODERANGE_UNKNOWN, NULL);
3837}
3838
3839VALUE
3841{
3842 /* ptr must reference NUL terminated ASCII string. */
3843 int encindex = ENCODING_GET(str);
3844 rb_encoding *enc = rb_enc_from_index(encindex);
3845 if (rb_enc_asciicompat(enc)) {
3846 return rb_enc_cr_str_buf_cat(str, ptr, strlen(ptr),
3847 encindex, ENC_CODERANGE_7BIT, 0);
3848 }
3849 else {
3850 char *buf = ALLOCA_N(char, rb_enc_mbmaxlen(enc));
3851 while (*ptr) {
3852 unsigned int c = (unsigned char)*ptr;
3853 int len = rb_enc_codelen(c, enc);
3854 rb_enc_mbcput(c, buf, enc);
3855 rb_enc_cr_str_buf_cat(str, buf, len,
3856 encindex, ENC_CODERANGE_VALID, 0);
3857 ptr++;
3858 }
3859 return str;
3860 }
3861}
3862
3863VALUE
3865{
3866 int str2_cr = rb_enc_str_coderange(str2);
3867
3868 if (rb_str_enc_fastpath(str)) {
3869 switch (str2_cr) {
3870 case ENC_CODERANGE_7BIT:
3871 // If RHS is 7bit we can do simple concatenation
3872 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3873 RB_GC_GUARD(str2);
3874 return str;
3876 // If RHS is valid, we can do simple concatenation if encodings are the same
3877 if (ENCODING_GET_INLINED(str) == ENCODING_GET_INLINED(str2)) {
3878 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3879 int str_cr = ENC_CODERANGE(str);
3880 if (UNLIKELY(str_cr != ENC_CODERANGE_VALID)) {
3881 ENC_CODERANGE_SET(str, RB_ENC_CODERANGE_AND(str_cr, str2_cr));
3882 }
3883 RB_GC_GUARD(str2);
3884 return str;
3885 }
3886 }
3887 }
3888
3889 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3890 ENCODING_GET(str2), str2_cr, &str2_cr);
3891
3892 ENC_CODERANGE_SET(str2, str2_cr);
3893
3894 return str;
3895}
3896
3897VALUE
3899{
3900 StringValue(str2);
3901 return rb_str_buf_append(str, str2);
3902}
3903
3904VALUE
3905rb_str_concat_literals(size_t num, const VALUE *strary)
3906{
3907 VALUE str;
3908 size_t i, s = 0;
3909 unsigned long len = 1;
3910
3911 if (UNLIKELY(!num)) return rb_str_new(0, 0);
3912 if (UNLIKELY(num == 1)) return rb_str_resurrect(strary[0]);
3913
3914 for (i = 0; i < num; ++i) { len += RSTRING_LEN(strary[i]); }
3915 str = rb_str_buf_new(len);
3916 str_enc_copy_direct(str, strary[0]);
3917
3918 for (i = s; i < num; ++i) {
3919 const VALUE v = strary[i];
3920 int encidx = ENCODING_GET(v);
3921
3922 rb_str_buf_append(str, v);
3923 if (encidx != ENCINDEX_US_ASCII) {
3924 if (ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)
3925 rb_enc_set_index(str, encidx);
3926 }
3927 }
3928 return str;
3929}
3930
3931/*
3932 * call-seq:
3933 * concat(*objects) -> string
3934 *
3935 * :include: doc/string/concat.rdoc
3936 */
3937static VALUE
3938rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
3939{
3940 str_modifiable(str);
3941
3942 if (argc == 1) {
3943 return rb_str_concat(str, argv[0]);
3944 }
3945 else if (argc > 1) {
3946 int i;
3947 VALUE arg_str = rb_str_tmp_new(0);
3948 rb_enc_copy(arg_str, str);
3949 for (i = 0; i < argc; i++) {
3950 rb_str_concat(arg_str, argv[i]);
3951 }
3952 rb_str_buf_append(str, arg_str);
3953 }
3954
3955 return str;
3956}
3957
3958/*
3959 * call-seq:
3960 * append_as_bytes(*objects) -> self
3961 *
3962 * Concatenates each object in +objects+ into +self+; returns +self+;
3963 * performs no encoding validation or conversion:
3964 *
3965 * s = 'foo'
3966 * s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82"
3967 * s.valid_encoding? # => false
3968 * s.append_as_bytes("\xAC 12")
3969 * s.valid_encoding? # => true
3970 *
3971 * When a given object is an integer,
3972 * the value is considered an 8-bit byte;
3973 * if the integer occupies more than one byte (i.e,. is greater than 255),
3974 * appends only the low-order byte (similar to String#setbyte):
3975 *
3976 * s = ""
3977 * s.append_as_bytes(0, 257) # => "\u0000\u0001"
3978 * s.bytesize # => 2
3979 *
3980 * Related: see {Modifying}[rdoc-ref:String@Modifying].
3981 */
3982
3983VALUE
3984rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
3985{
3986 long needed_capacity = 0;
3987 volatile VALUE t0;
3988 enum ruby_value_type *types = ALLOCV_N(enum ruby_value_type, t0, argc);
3989
3990 for (int index = 0; index < argc; index++) {
3991 VALUE obj = argv[index];
3992 enum ruby_value_type type = types[index] = rb_type(obj);
3993 switch (type) {
3994 case T_FIXNUM:
3995 case T_BIGNUM:
3996 needed_capacity++;
3997 break;
3998 case T_STRING:
3999 needed_capacity += RSTRING_LEN(obj);
4000 break;
4001 default:
4002 rb_raise(
4004 "wrong argument type %"PRIsVALUE" (expected String or Integer)",
4005 rb_obj_class(obj)
4006 );
4007 break;
4008 }
4009 }
4010
4011 str_ensure_available_capa(str, needed_capacity);
4012 char *sptr = RSTRING_END(str);
4013
4014 for (int index = 0; index < argc; index++) {
4015 VALUE obj = argv[index];
4016 enum ruby_value_type type = types[index];
4017 switch (type) {
4018 case T_FIXNUM:
4019 case T_BIGNUM: {
4020 argv[index] = obj = rb_int_and(obj, INT2FIX(0xff));
4021 char byte = (char)(NUM2INT(obj) & 0xFF);
4022 *sptr = byte;
4023 sptr++;
4024 break;
4025 }
4026 case T_STRING: {
4027 const char *ptr;
4028 long len;
4029 RSTRING_GETMEM(obj, ptr, len);
4030 memcpy(sptr, ptr, len);
4031 sptr += len;
4032 break;
4033 }
4034 default:
4035 rb_bug("append_as_bytes arguments should have been validated");
4036 }
4037 }
4038
4039 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
4040 TERM_FILL(sptr, TERM_LEN(str)); /* sentinel */
4041
4042 int cr = ENC_CODERANGE(str);
4043 switch (cr) {
4044 case ENC_CODERANGE_7BIT: {
4045 for (int index = 0; index < argc; index++) {
4046 VALUE obj = argv[index];
4047 enum ruby_value_type type = types[index];
4048 switch (type) {
4049 case T_FIXNUM:
4050 case T_BIGNUM: {
4051 if (!ISASCII(NUM2INT(obj))) {
4052 goto clear_cr;
4053 }
4054 break;
4055 }
4056 case T_STRING: {
4057 if (ENC_CODERANGE(obj) != ENC_CODERANGE_7BIT) {
4058 goto clear_cr;
4059 }
4060 break;
4061 }
4062 default:
4063 rb_bug("append_as_bytes arguments should have been validated");
4064 }
4065 }
4066 break;
4067 }
4069 if (ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT) {
4070 goto keep_cr;
4071 }
4072 else {
4073 goto clear_cr;
4074 }
4075 break;
4076 default:
4077 goto clear_cr;
4078 break;
4079 }
4080
4081 RB_GC_GUARD(t0);
4082
4083 clear_cr:
4084 // If no fast path was hit, we clear the coderange.
4085 // append_as_bytes is predominantly meant to be used in
4086 // buffering situation, hence it's likely the coderange
4087 // will never be scanned, so it's not worth spending time
4088 // precomputing the coderange except for simple and common
4089 // situations.
4091 keep_cr:
4092 return str;
4093}
4094
4095/*
4096 * call-seq:
4097 * self << object -> self
4098 *
4099 * Appends a string representation of +object+ to +self+;
4100 * returns +self+.
4101 *
4102 * If +object+ is a string, appends it to +self+:
4103 *
4104 * s = 'foo'
4105 * s << 'bar' # => "foobar"
4106 * s # => "foobar"
4107 *
4108 * If +object+ is an integer,
4109 * its value is considered a codepoint;
4110 * converts the value to a character before concatenating:
4111 *
4112 * s = 'foo'
4113 * s << 33 # => "foo!"
4114 *
4115 * Additionally, if the codepoint is in range <tt>0..0xff</tt>
4116 * and the encoding of +self+ is Encoding::US_ASCII,
4117 * changes the encoding to Encoding::ASCII_8BIT:
4118 *
4119 * s = 'foo'.encode(Encoding::US_ASCII)
4120 * s.encoding # => #<Encoding:US-ASCII>
4121 * s << 0xff # => "foo\xFF"
4122 * s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
4123 *
4124 * Raises RangeError if that codepoint is not representable in the encoding of +self+:
4125 *
4126 * s = 'foo'
4127 * s.encoding # => <Encoding:UTF-8>
4128 * s << 0x00110000 # 1114112 out of char range (RangeError)
4129 * s = 'foo'.encode(Encoding::EUC_JP)
4130 * s << 0x00800080 # invalid codepoint 0x800080 in EUC-JP (RangeError)
4131 *
4132 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4133 */
4134VALUE
4136{
4137 unsigned int code;
4138 rb_encoding *enc = STR_ENC_GET(str1);
4139 int encidx;
4140
4141 if (RB_INTEGER_TYPE_P(str2)) {
4142 if (rb_num_to_uint(str2, &code) == 0) {
4143 }
4144 else if (FIXNUM_P(str2)) {
4145 rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(str2));
4146 }
4147 else {
4148 rb_raise(rb_eRangeError, "bignum out of char range");
4149 }
4150 }
4151 else {
4152 return rb_str_append(str1, str2);
4153 }
4154
4155 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4156
4157 if (encidx >= 0) {
4158 rb_str_buf_cat_byte(str1, (unsigned char)code);
4159 }
4160 else {
4161 long pos = RSTRING_LEN(str1);
4162 int cr = ENC_CODERANGE(str1);
4163 int len;
4164 char *buf;
4165
4166 switch (len = rb_enc_codelen(code, enc)) {
4167 case ONIGERR_INVALID_CODE_POINT_VALUE:
4168 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4169 break;
4170 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4171 case 0:
4172 rb_raise(rb_eRangeError, "%u out of char range", code);
4173 break;
4174 }
4175 buf = ALLOCA_N(char, len + 1);
4176 rb_enc_mbcput(code, buf, enc);
4177 if (rb_enc_precise_mbclen(buf, buf + len + 1, enc) != len) {
4178 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4179 }
4180 rb_str_resize(str1, pos+len);
4181 memcpy(RSTRING_PTR(str1) + pos, buf, len);
4182 if (cr == ENC_CODERANGE_7BIT && code > 127) {
4184 }
4185 else if (cr == ENC_CODERANGE_BROKEN) {
4187 }
4188 ENC_CODERANGE_SET(str1, cr);
4189 }
4190 return str1;
4191}
4192
4193int
4194rb_ascii8bit_appendable_encoding_index(rb_encoding *enc, unsigned int code)
4195{
4196 int encidx = rb_enc_to_index(enc);
4197
4198 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4199 /* US-ASCII automatically extended to ASCII-8BIT */
4200 if (code > 0xFF) {
4201 rb_raise(rb_eRangeError, "%u out of char range", code);
4202 }
4203 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4204 return ENCINDEX_ASCII_8BIT;
4205 }
4206 return encidx;
4207 }
4208 else {
4209 return -1;
4210 }
4211}
4212
4213/*
4214 * call-seq:
4215 * prepend(*other_strings) -> new_string
4216 *
4217 * Prefixes to +self+ the concatenation of the given +other_strings+; returns +self+:
4218 *
4219 * 'baz'.prepend('foo', 'bar') # => "foobarbaz"
4220 *
4221 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4222 *
4223 */
4224
4225static VALUE
4226rb_str_prepend_multi(int argc, VALUE *argv, VALUE str)
4227{
4228 str_modifiable(str);
4229
4230 if (argc == 1) {
4231 rb_str_update(str, 0L, 0L, argv[0]);
4232 }
4233 else if (argc > 1) {
4234 int i;
4235 VALUE arg_str = rb_str_tmp_new(0);
4236 rb_enc_copy(arg_str, str);
4237 for (i = 0; i < argc; i++) {
4238 rb_str_append(arg_str, argv[i]);
4239 }
4240 rb_str_update(str, 0L, 0L, arg_str);
4241 }
4242
4243 return str;
4244}
4245
4246st_index_t
4248{
4249 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) {
4250 st_index_t precomputed_hash;
4251 memcpy(&precomputed_hash, RSTRING_END(str) + TERM_LEN(str), sizeof(precomputed_hash));
4252
4253 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4254 return precomputed_hash;
4255 }
4256
4257 return str_do_hash(str);
4258}
4259
4260int
4262{
4263 long len1, len2;
4264 const char *ptr1, *ptr2;
4265 RSTRING_GETMEM(str1, ptr1, len1);
4266 RSTRING_GETMEM(str2, ptr2, len2);
4267 return (len1 != len2 ||
4268 !rb_str_comparable(str1, str2) ||
4269 memcmp(ptr1, ptr2, len1) != 0);
4270}
4271
4272/*
4273 * call-seq:
4274 * hash -> integer
4275 *
4276 * :include: doc/string/hash.rdoc
4277 *
4278 */
4279
4280static VALUE
4281rb_str_hash_m(VALUE str)
4282{
4283 st_index_t hval = rb_str_hash(str);
4284 return ST2FIX(hval);
4285}
4286
4287#define lesser(a,b) (((a)>(b))?(b):(a))
4288
4289int
4291{
4292 int idx1, idx2;
4293 int rc1, rc2;
4294
4295 if (RSTRING_LEN(str1) == 0) return TRUE;
4296 if (RSTRING_LEN(str2) == 0) return TRUE;
4297 idx1 = ENCODING_GET(str1);
4298 idx2 = ENCODING_GET(str2);
4299 if (idx1 == idx2) return TRUE;
4300 rc1 = rb_enc_str_coderange(str1);
4301 rc2 = rb_enc_str_coderange(str2);
4302 if (rc1 == ENC_CODERANGE_7BIT) {
4303 if (rc2 == ENC_CODERANGE_7BIT) return TRUE;
4304 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4305 return TRUE;
4306 }
4307 if (rc2 == ENC_CODERANGE_7BIT) {
4308 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4309 return TRUE;
4310 }
4311 return FALSE;
4312}
4313
4314int
4316{
4317 long len1, len2;
4318 const char *ptr1, *ptr2;
4319 int retval;
4320
4321 if (str1 == str2) return 0;
4322 RSTRING_GETMEM(str1, ptr1, len1);
4323 RSTRING_GETMEM(str2, ptr2, len2);
4324 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4325 if (len1 == len2) {
4326 if (!rb_str_comparable(str1, str2)) {
4327 if (ENCODING_GET(str1) > ENCODING_GET(str2))
4328 return 1;
4329 return -1;
4330 }
4331 return 0;
4332 }
4333 if (len1 > len2) return 1;
4334 return -1;
4335 }
4336 if (retval > 0) return 1;
4337 return -1;
4338}
4339
4340/*
4341 * call-seq:
4342 * self == other -> true or false
4343 *
4344 * Returns whether +other+ is equal to +self+.
4345 *
4346 * When +other+ is a string, returns whether +other+ has the same length and content as +self+:
4347 *
4348 * s = 'foo'
4349 * s == 'foo' # => true
4350 * s == 'food' # => false
4351 * s == 'FOO' # => false
4352 *
4353 * Returns +false+ if the two strings' encodings are not compatible:
4354 *
4355 * "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false
4356 *
4357 * When +other+ is not a string:
4358 *
4359 * - If +other+ responds to method <tt>to_str</tt>,
4360 * <tt>other == self</tt> is called and its return value is returned.
4361 * - If +other+ does not respond to <tt>to_str</tt>,
4362 * +false+ is returned.
4363 *
4364 * Related: {Comparing}[rdoc-ref:String@Comparing].
4365 */
4366
4367VALUE
4369{
4370 if (str1 == str2) return Qtrue;
4371 if (!RB_TYPE_P(str2, T_STRING)) {
4372 if (!rb_respond_to(str2, idTo_str)) {
4373 return Qfalse;
4374 }
4375 return rb_equal(str2, str1);
4376 }
4377 return rb_str_eql_internal(str1, str2);
4378}
4379
4380/*
4381 * call-seq:
4382 * eql?(object) -> true or false
4383 *
4384 * :include: doc/string/eql_p.rdoc
4385 *
4386 */
4387
4388VALUE
4389rb_str_eql(VALUE str1, VALUE str2)
4390{
4391 if (str1 == str2) return Qtrue;
4392 if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
4393 return rb_str_eql_internal(str1, str2);
4394}
4395
4396/*
4397 * call-seq:
4398 * self <=> other -> -1, 0, 1, or nil
4399 *
4400 * Compares +self+ and +other+,
4401 * evaluating their _contents_, not their _lengths_.
4402 *
4403 * Returns:
4404 *
4405 * - +-1+, if +self+ is smaller.
4406 * - +0+, if the two are equal.
4407 * - +1+, if +self+ is larger.
4408 * - +nil+, if the two are incomparable.
4409 *
4410 * Examples:
4411 *
4412 * 'a' <=> 'b' # => -1
4413 * 'a' <=> 'ab' # => -1
4414 * 'a' <=> 'a' # => 0
4415 * 'b' <=> 'a' # => 1
4416 * 'ab' <=> 'a' # => 1
4417 * 'a' <=> :a # => nil
4418 *
4419 * \Class \String includes module Comparable,
4420 * each of whose methods uses String#<=> for comparison.
4421 *
4422 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4423 */
4424
4425static VALUE
4426rb_str_cmp_m(VALUE str1, VALUE str2)
4427{
4428 int result;
4429 VALUE s = rb_check_string_type(str2);
4430 if (NIL_P(s)) {
4431 return rb_invcmp(str1, str2);
4432 }
4433 result = rb_str_cmp(str1, s);
4434 return INT2FIX(result);
4435}
4436
4437static VALUE str_casecmp(VALUE str1, VALUE str2);
4438static VALUE str_casecmp_p(VALUE str1, VALUE str2);
4439
4440/*
4441 * call-seq:
4442 * casecmp(other_string) -> -1, 0, 1, or nil
4443 *
4444 * Ignoring case, compares +self+ and +other_string+; returns:
4445 *
4446 * - -1 if <tt>self.downcase</tt> is smaller than <tt>other_string.downcase</tt>.
4447 * - 0 if the two are equal.
4448 * - 1 if <tt>self.downcase</tt> is larger than <tt>other_string.downcase</tt>.
4449 * - +nil+ if the two are incomparable.
4450 *
4451 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4452 *
4453 * Examples:
4454 *
4455 * 'foo'.casecmp('goo') # => -1
4456 * 'goo'.casecmp('foo') # => 1
4457 * 'foo'.casecmp('food') # => -1
4458 * 'food'.casecmp('foo') # => 1
4459 * 'FOO'.casecmp('foo') # => 0
4460 * 'foo'.casecmp('FOO') # => 0
4461 * 'foo'.casecmp(1) # => nil
4462 *
4463 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4464 */
4465
4466VALUE
4467rb_str_casecmp(VALUE str1, VALUE str2)
4468{
4469 VALUE s = rb_check_string_type(str2);
4470 if (NIL_P(s)) {
4471 return Qnil;
4472 }
4473 return str_casecmp(str1, s);
4474}
4475
4476static VALUE
4477str_casecmp(VALUE str1, VALUE str2)
4478{
4479 long len;
4480 rb_encoding *enc;
4481 const char *p1, *p1end, *p2, *p2end;
4482
4483 enc = rb_enc_compatible(str1, str2);
4484 if (!enc) {
4485 return Qnil;
4486 }
4487
4488 p1 = RSTRING_PTR(str1); p1end = RSTRING_END(str1);
4489 p2 = RSTRING_PTR(str2); p2end = RSTRING_END(str2);
4490 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4491 while (p1 < p1end && p2 < p2end) {
4492 if (*p1 != *p2) {
4493 unsigned int c1 = TOLOWER(*p1 & 0xff);
4494 unsigned int c2 = TOLOWER(*p2 & 0xff);
4495 if (c1 != c2)
4496 return INT2FIX(c1 < c2 ? -1 : 1);
4497 }
4498 p1++;
4499 p2++;
4500 }
4501 }
4502 else {
4503 while (p1 < p1end && p2 < p2end) {
4504 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4505 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4506
4507 if (0 <= c1 && 0 <= c2) {
4508 c1 = TOLOWER(c1);
4509 c2 = TOLOWER(c2);
4510 if (c1 != c2)
4511 return INT2FIX(c1 < c2 ? -1 : 1);
4512 }
4513 else {
4514 int r;
4515 l1 = rb_enc_mbclen(p1, p1end, enc);
4516 l2 = rb_enc_mbclen(p2, p2end, enc);
4517 len = l1 < l2 ? l1 : l2;
4518 r = memcmp(p1, p2, len);
4519 if (r != 0)
4520 return INT2FIX(r < 0 ? -1 : 1);
4521 if (l1 != l2)
4522 return INT2FIX(l1 < l2 ? -1 : 1);
4523 }
4524 p1 += l1;
4525 p2 += l2;
4526 }
4527 }
4528 if (p1 == p1end && p2 == p2end) return INT2FIX(0);
4529 if (p1 == p1end) return INT2FIX(-1);
4530 return INT2FIX(1);
4531}
4532
4533/*
4534 * call-seq:
4535 * casecmp?(other_string) -> true, false, or nil
4536 *
4537 * Returns +true+ if +self+ and +other_string+ are equal after
4538 * Unicode case folding, +false+ if unequal, +nil+ if incomparable.
4539 *
4540 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4541 *
4542 * Examples:
4543 *
4544 * 'foo'.casecmp?('goo') # => false
4545 * 'goo'.casecmp?('foo') # => false
4546 * 'foo'.casecmp?('food') # => false
4547 * 'food'.casecmp?('foo') # => false
4548 * 'FOO'.casecmp?('foo') # => true
4549 * 'foo'.casecmp?('FOO') # => true
4550 * 'foo'.casecmp?(1) # => nil
4551 *
4552 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4553 */
4554
4555static VALUE
4556rb_str_casecmp_p(VALUE str1, VALUE str2)
4557{
4558 VALUE s = rb_check_string_type(str2);
4559 if (NIL_P(s)) {
4560 return Qnil;
4561 }
4562 return str_casecmp_p(str1, s);
4563}
4564
4565static VALUE
4566str_casecmp_p(VALUE str1, VALUE str2)
4567{
4568 rb_encoding *enc;
4569 VALUE folded_str1, folded_str2;
4570 VALUE fold_opt = sym_fold;
4571
4572 enc = rb_enc_compatible(str1, str2);
4573 if (!enc) {
4574 return Qnil;
4575 }
4576
4577 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4578 if (RSTRING_LEN(str1) != RSTRING_LEN(str2)) return Qfalse;
4579 const char *p1 = RSTRING_PTR(str1), *p1end = RSTRING_END(str1);
4580 const char *p2 = RSTRING_PTR(str2);
4581 while (p1 < p1end) {
4582 if (*p1 != *p2 && TOLOWER((unsigned char)*p1) != TOLOWER((unsigned char)*p2)) {
4583 return Qfalse;
4584 }
4585 p1++;
4586 p2++;
4587 }
4588 return Qtrue;
4589 }
4590
4591 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4592 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4593
4594 return rb_str_eql(folded_str1, folded_str2);
4595}
4596
4597static long
4598strseq_core(const char *str_ptr, const char *str_ptr_end, long str_len,
4599 const char *sub_ptr, long sub_len, long offset, rb_encoding *enc)
4600{
4601 const char *search_start = str_ptr;
4602 long pos, search_len = str_len - offset;
4603
4604 for (;;) {
4605 const char *t;
4606 pos = rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4607 if (pos < 0) return pos;
4608 t = rb_enc_right_char_head(search_start, search_start+pos, str_ptr_end, enc);
4609 if (t == search_start + pos) break;
4610 search_len -= t - search_start;
4611 if (search_len <= 0) return -1;
4612 offset += t - search_start;
4613 search_start = t;
4614 }
4615 return pos + offset;
4616}
4617
4618/* found index in byte */
4619#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4620#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4621
4622static long
4623rb_strseq_index(VALUE str, VALUE sub, long offset, int in_byte)
4624{
4625 const char *str_ptr, *str_ptr_end, *sub_ptr;
4626 long str_len, sub_len;
4627 rb_encoding *enc;
4628
4629 enc = rb_enc_check(str, sub);
4630 if (is_broken_string(sub)) return -1;
4631
4632 str_ptr = RSTRING_PTR(str);
4633 str_ptr_end = RSTRING_END(str);
4634 str_len = RSTRING_LEN(str);
4635 sub_ptr = RSTRING_PTR(sub);
4636 sub_len = RSTRING_LEN(sub);
4637
4638 if (str_len < sub_len) return -1;
4639
4640 if (offset != 0) {
4641 long str_len_char, sub_len_char;
4642 int single_byte = single_byte_optimizable(str);
4643 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4644 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4645 if (offset < 0) {
4646 offset += str_len_char;
4647 if (offset < 0) return -1;
4648 }
4649 if (str_len_char - offset < sub_len_char) return -1;
4650 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4651 str_ptr += offset;
4652 }
4653 if (sub_len == 0) return offset;
4654
4655 /* need proceed one character at a time */
4656 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4657}
4658
4659
4660/*
4661 * call-seq:
4662 * index(pattern, offset = 0) -> integer or nil
4663 *
4664 * :include: doc/string/index.rdoc
4665 *
4666 */
4667
4668static VALUE
4669rb_str_index_m(int argc, VALUE *argv, VALUE str)
4670{
4671 VALUE sub;
4672 VALUE initpos;
4673 rb_encoding *enc = STR_ENC_GET(str);
4674 long pos;
4675
4676 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4677 long slen = str_strlen(str, enc); /* str's enc */
4678 pos = NUM2LONG(initpos);
4679 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4680 if (RB_TYPE_P(sub, T_REGEXP)) {
4682 }
4683 return Qnil;
4684 }
4685 }
4686 else {
4687 pos = 0;
4688 }
4689
4690 if (RB_TYPE_P(sub, T_REGEXP)) {
4691 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4692 enc, single_byte_optimizable(str));
4693
4694 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4695 VALUE match = rb_backref_get();
4696 pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
4697 return LONG2NUM(pos);
4698 }
4699 }
4700 else {
4701 StringValue(sub);
4702 pos = rb_str_index(str, sub, pos);
4703 if (pos >= 0) {
4704 pos = rb_str_sublen(str, pos);
4705 return LONG2NUM(pos);
4706 }
4707 }
4708 return Qnil;
4709}
4710
4711/* Ensure that the given pos is a valid character boundary.
4712 * Note that in this function, "character" means a code point
4713 * (Unicode scalar value), not a grapheme cluster.
4714 */
4715static void
4716str_ensure_byte_pos(VALUE str, long pos)
4717{
4718 if (!single_byte_optimizable(str)) {
4719 const char *s = RSTRING_PTR(str);
4720 const char *e = RSTRING_END(str);
4721 const char *p = s + pos;
4722 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4723 rb_raise(rb_eIndexError,
4724 "offset %ld does not land on character boundary", pos);
4725 }
4726 }
4727}
4728
4729/*
4730 * call-seq:
4731 * byteindex(object, offset = 0) -> integer or nil
4732 *
4733 * Returns the 0-based integer index of a substring of +self+
4734 * specified by +object+ (a string or Regexp) and +offset+,
4735 * or +nil+ if there is no such substring;
4736 * the returned index is the count of _bytes_ (not characters).
4737 *
4738 * When +object+ is a string,
4739 * returns the index of the first found substring equal to +object+:
4740 *
4741 * s = 'foo' # => "foo"
4742 * s.size # => 3 # Three 1-byte characters.
4743 * s.bytesize # => 3 # Three bytes.
4744 * s.byteindex('f') # => 0
4745 * s.byteindex('o') # => 1
4746 * s.byteindex('oo') # => 1
4747 * s.byteindex('ooo') # => nil
4748 *
4749 * When +object+ is a Regexp,
4750 * returns the index of the first found substring matching +object+;
4751 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
4752 *
4753 * s = 'foo'
4754 * s.byteindex(/f/) # => 0
4755 * $~ # => #<MatchData "f">
4756 * s.byteindex(/o/) # => 1
4757 * s.byteindex(/oo/) # => 1
4758 * s.byteindex(/ooo/) # => nil
4759 * $~ # => nil
4760 *
4761 * \Integer argument +offset+, if given, specifies the 0-based index
4762 * of the byte where searching is to begin.
4763 *
4764 * When +offset+ is non-negative,
4765 * searching begins at byte position +offset+:
4766 *
4767 * s = 'foo'
4768 * s.byteindex('o', 1) # => 1
4769 * s.byteindex('o', 2) # => 2
4770 * s.byteindex('o', 3) # => nil
4771 *
4772 * When +offset+ is negative, counts backward from the end of +self+:
4773 *
4774 * s = 'foo'
4775 * s.byteindex('o', -1) # => 2
4776 * s.byteindex('o', -2) # => 1
4777 * s.byteindex('o', -3) # => 1
4778 * s.byteindex('o', -4) # => nil
4779 *
4780 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
4781 *
4782 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
4783 * s.size # => 2 # Two 3-byte characters.
4784 * s.bytesize # => 6 # Six bytes.
4785 * s.byteindex("\uFFFF") # => 0
4786 * s.byteindex("\uFFFF", 1) # Raises IndexError
4787 * s.byteindex("\uFFFF", 2) # Raises IndexError
4788 * s.byteindex("\uFFFF", 3) # => 3
4789 * s.byteindex("\uFFFF", 4) # Raises IndexError
4790 * s.byteindex("\uFFFF", 5) # Raises IndexError
4791 * s.byteindex("\uFFFF", 6) # => nil
4792 *
4793 * Related: see {Querying}[rdoc-ref:String@Querying].
4794 */
4795
4796static VALUE
4797rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
4798{
4799 VALUE sub;
4800 VALUE initpos;
4801 long pos;
4802
4803 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4804 long slen = RSTRING_LEN(str);
4805 pos = NUM2LONG(initpos);
4806 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4807 if (RB_TYPE_P(sub, T_REGEXP)) {
4809 }
4810 return Qnil;
4811 }
4812 }
4813 else {
4814 pos = 0;
4815 }
4816
4817 str_ensure_byte_pos(str, pos);
4818
4819 if (RB_TYPE_P(sub, T_REGEXP)) {
4820 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4821 VALUE match = rb_backref_get();
4822 pos = RMATCH_BEG(match, 0);
4823 return LONG2NUM(pos);
4824 }
4825 }
4826 else {
4827 StringValue(sub);
4828 pos = rb_str_byteindex(str, sub, pos);
4829 if (pos >= 0) return LONG2NUM(pos);
4830 }
4831 return Qnil;
4832}
4833
4834static long
4835str_rindex(VALUE str, VALUE sub, const char *s, rb_encoding *enc)
4836{
4837 const char *hit, *adjusted, *sbeg, *e, *t;
4838 int c;
4839 long slen, searchlen;
4840
4841 sbeg = RSTRING_PTR(str);
4842 slen = RSTRING_LEN(sub);
4843 if (slen == 0) return s - sbeg;
4844 e = RSTRING_END(str);
4845 t = RSTRING_PTR(sub);
4846 c = *t & 0xff;
4847 searchlen = s - sbeg + 1;
4848
4849 if (memcmp(s, t, slen) == 0) {
4850 return s - sbeg;
4851 }
4852
4853 do {
4854 hit = memrchr(sbeg, c, searchlen);
4855 if (!hit) break;
4856 adjusted = rb_enc_left_char_head(sbeg, hit, e, enc);
4857 if (hit != adjusted) {
4858 searchlen = adjusted - sbeg;
4859 continue;
4860 }
4861 if (memcmp(hit, t, slen) == 0)
4862 return hit - sbeg;
4863 searchlen = adjusted - sbeg;
4864 } while (searchlen > 0);
4865
4866 return -1;
4867}
4868
4869/* found index in byte */
4870static long
4871rb_str_rindex(VALUE str, VALUE sub, long pos)
4872{
4873 long len, slen;
4874 const char *sbeg, *s;
4875 rb_encoding *enc;
4876 int singlebyte;
4877
4878 enc = rb_enc_check(str, sub);
4879 if (is_broken_string(sub)) return -1;
4880 singlebyte = single_byte_optimizable(str);
4881 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc); /* rb_enc_check */
4882 slen = str_strlen(sub, enc); /* rb_enc_check */
4883
4884 /* substring longer than string */
4885 if (len < slen) return -1;
4886 if (len - pos < slen) pos = len - slen;
4887 if (len == 0) return pos;
4888
4889 sbeg = RSTRING_PTR(str);
4890
4891 if (pos == 0) {
4892 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4893 return 0;
4894 else
4895 return -1;
4896 }
4897
4898 s = str_nth(sbeg, RSTRING_END(str), pos, enc, singlebyte);
4899 return str_rindex(str, sub, s, enc);
4900}
4901
4902/*
4903 * call-seq:
4904 * rindex(pattern, offset = self.length) -> integer or nil
4905 *
4906 * :include:doc/string/rindex.rdoc
4907 *
4908 */
4909
4910static VALUE
4911rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
4912{
4913 VALUE sub;
4914 VALUE initpos;
4915 rb_encoding *enc = STR_ENC_GET(str);
4916 long pos, len = str_strlen(str, enc); /* str's enc */
4917
4918 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4919 pos = NUM2LONG(initpos);
4920 if (pos < 0 && (pos += len) < 0) {
4921 if (RB_TYPE_P(sub, T_REGEXP)) {
4923 }
4924 return Qnil;
4925 }
4926 if (pos > len) pos = len;
4927 }
4928 else {
4929 pos = len;
4930 }
4931
4932 if (RB_TYPE_P(sub, T_REGEXP)) {
4933 /* enc = rb_enc_check(str, sub); */
4934 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4935 enc, single_byte_optimizable(str));
4936
4937 if (rb_reg_search(sub, str, pos, 1) >= 0) {
4938 VALUE match = rb_backref_get();
4939 pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
4940 return LONG2NUM(pos);
4941 }
4942 }
4943 else {
4944 StringValue(sub);
4945 pos = rb_str_rindex(str, sub, pos);
4946 if (pos >= 0) {
4947 pos = rb_str_sublen(str, pos);
4948 return LONG2NUM(pos);
4949 }
4950 }
4951 return Qnil;
4952}
4953
4954static long
4955rb_str_byterindex(VALUE str, VALUE sub, long pos)
4956{
4957 long len, slen;
4958 const char *sbeg, *s;
4959 rb_encoding *enc;
4960
4961 enc = rb_enc_check(str, sub);
4962 if (is_broken_string(sub)) return -1;
4963 len = RSTRING_LEN(str);
4964 slen = RSTRING_LEN(sub);
4965
4966 /* substring longer than string */
4967 if (len < slen) return -1;
4968 if (len - pos < slen) pos = len - slen;
4969 if (len == 0) return pos;
4970
4971 sbeg = RSTRING_PTR(str);
4972
4973 if (pos == 0) {
4974 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4975 return 0;
4976 else
4977 return -1;
4978 }
4979
4980 s = sbeg + pos;
4981 return str_rindex(str, sub, s, enc);
4982}
4983
4984/*
4985 * call-seq:
4986 * byterindex(object, offset = self.bytesize) -> integer or nil
4987 *
4988 * Returns the 0-based integer index of a substring of +self+
4989 * that is the _last_ match for the given +object+ (a string or Regexp) and +offset+,
4990 * or +nil+ if there is no such substring;
4991 * the returned index is the count of _bytes_ (not characters).
4992 *
4993 * When +object+ is a string,
4994 * returns the index of the _last_ found substring equal to +object+:
4995 *
4996 * s = 'foo' # => "foo"
4997 * s.size # => 3 # Three 1-byte characters.
4998 * s.bytesize # => 3 # Three bytes.
4999 * s.byterindex('f') # => 0
5000 * s.byterindex('o') # => 2
5001 * s.byterindex('oo') # => 1
5002 * s.byterindex('ooo') # => nil
5003 *
5004 * When +object+ is a Regexp,
5005 * returns the index of the last found substring matching +object+;
5006 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
5007 *
5008 * s = 'foo'
5009 * s.byterindex(/f/) # => 0
5010 * $~ # => #<MatchData "f">
5011 * s.byterindex(/o/) # => 2
5012 * s.byterindex(/oo/) # => 1
5013 * s.byterindex(/ooo/) # => nil
5014 * $~ # => nil
5015 *
5016 * The last match means starting at the possible last position,
5017 * not the last of the longest matches:
5018 *
5019 * s = 'foo'
5020 * s.byterindex(/o+/) # => 2
5021 * $~ #=> #<MatchData "o">
5022 *
5023 * To get the last longest match, use a negative lookbehind:
5024 *
5025 * s = 'foo'
5026 * s.byterindex(/(?<!o)o+/) # => 1
5027 * $~ # => #<MatchData "oo">
5028 *
5029 * Or use method #byteindex with negative lookahead:
5030 *
5031 * s = 'foo'
5032 * s.byteindex(/o+(?!.*o)/) # => 1
5033 * $~ #=> #<MatchData "oo">
5034 *
5035 * \Integer argument +offset+, if given, specifies the 0-based index
5036 * of the byte where searching is to end.
5037 *
5038 * When +offset+ is non-negative,
5039 * searching ends at byte position +offset+:
5040 *
5041 * s = 'foo'
5042 * s.byterindex('o', 0) # => nil
5043 * s.byterindex('o', 1) # => 1
5044 * s.byterindex('o', 2) # => 2
5045 * s.byterindex('o', 3) # => 2
5046 *
5047 * When +offset+ is negative, counts backward from the end of +self+:
5048 *
5049 * s = 'foo'
5050 * s.byterindex('o', -1) # => 2
5051 * s.byterindex('o', -2) # => 1
5052 * s.byterindex('o', -3) # => nil
5053 *
5054 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
5055 *
5056 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
5057 * s.size # => 2 # Two 3-byte characters.
5058 * s.bytesize # => 6 # Six bytes.
5059 * s.byterindex("\uFFFF") # => 3
5060 * s.byterindex("\uFFFF", 1) # Raises IndexError
5061 * s.byterindex("\uFFFF", 2) # Raises IndexError
5062 * s.byterindex("\uFFFF", 3) # => 3
5063 * s.byterindex("\uFFFF", 4) # Raises IndexError
5064 * s.byterindex("\uFFFF", 5) # Raises IndexError
5065 * s.byterindex("\uFFFF", 6) # => nil
5066 *
5067 * Related: see {Querying}[rdoc-ref:String@Querying].
5068 */
5069
5070static VALUE
5071rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
5072{
5073 VALUE sub;
5074 VALUE initpos;
5075 long pos, len = RSTRING_LEN(str);
5076
5077 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
5078 pos = NUM2LONG(initpos);
5079 if (pos < 0 && (pos += len) < 0) {
5080 if (RB_TYPE_P(sub, T_REGEXP)) {
5082 }
5083 return Qnil;
5084 }
5085 if (pos > len) pos = len;
5086 }
5087 else {
5088 pos = len;
5089 }
5090
5091 str_ensure_byte_pos(str, pos);
5092
5093 if (RB_TYPE_P(sub, T_REGEXP)) {
5094 if (rb_reg_search(sub, str, pos, 1) >= 0) {
5095 VALUE match = rb_backref_get();
5096 pos = RMATCH_BEG(match, 0);
5097 return LONG2NUM(pos);
5098 }
5099 }
5100 else {
5101 StringValue(sub);
5102 pos = rb_str_byterindex(str, sub, pos);
5103 if (pos >= 0) return LONG2NUM(pos);
5104 }
5105 return Qnil;
5106}
5107
5108/*
5109 * call-seq:
5110 * self =~ other -> integer or nil
5111 *
5112 * When +other+ is a Regexp:
5113 *
5114 * - Returns the integer index (in characters) of the first match
5115 * for +self+ and +other+, or +nil+ if none;
5116 * - Updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
5117 *
5118 * Examples:
5119 *
5120 * 'foo' =~ /f/ # => 0
5121 * $~ # => #<MatchData "f">
5122 * 'foo' =~ /o/ # => 1
5123 * $~ # => #<MatchData "o">
5124 * 'foo' =~ /x/ # => nil
5125 * $~ # => nil
5126 *
5127 * Note that <tt>string =~ regexp</tt> is different from <tt>regexp =~ string</tt>
5128 * (see Regexp#=~):
5129 *
5130 * number = nil
5131 * 'no. 9' =~ /(?<number>\d+)/ # => 4
5132 * number # => nil # Not assigned.
5133 * /(?<number>\d+)/ =~ 'no. 9' # => 4
5134 * number # => "9" # Assigned.
5135 *
5136 * When +other+ is not a Regexp, returns the value
5137 * returned by <tt>other =~ self</tt>.
5138 *
5139 * Related: see {Querying}[rdoc-ref:String@Querying].
5140 */
5141
5142static VALUE
5143rb_str_match(VALUE x, VALUE y)
5144{
5145 switch (OBJ_BUILTIN_TYPE(y)) {
5146 case T_STRING:
5147 rb_raise(rb_eTypeError, "type mismatch: String given");
5148
5149 case T_REGEXP:
5150 return rb_reg_match(y, x);
5151
5152 default:
5153 return rb_funcall(y, idEqTilde, 1, x);
5154 }
5155}
5156
5157
5158static VALUE get_pat(VALUE);
5159
5160
5161/*
5162 * call-seq:
5163 * match(pattern, offset = 0) -> matchdata or nil
5164 * match(pattern, offset = 0) {|matchdata| ... } -> object
5165 *
5166 * Creates a MatchData object based on +self+ and the given arguments;
5167 * updates {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5168 *
5169 * - Computes +regexp+ by converting +pattern+ (if not already a Regexp).
5170 *
5171 * regexp = Regexp.new(pattern)
5172 *
5173 * - Calls <tt>regexp.match</tt> with +self+ to compute +matchdata+.
5174 * If +offset+ is given, it is also passed (see Regexp#match).
5175 *
5176 * With no block given, returns the computed +matchdata+ or +nil+:
5177 *
5178 * 'foo'.match('f') # => #<MatchData "f">
5179 * 'foo'.match('o') # => #<MatchData "o">
5180 * 'foo'.match('x') # => nil
5181 * 'foo'.match('f', 1) # => nil
5182 * 'foo'.match('o', 1) # => #<MatchData "o">
5183 *
5184 * With a block given and computed +matchdata+ non-nil, calls the block with +matchdata+;
5185 * returns the block's return value:
5186 *
5187 * 'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
5188 *
5189 * With a block given and +nil+ +matchdata+, does not call the block:
5190 *
5191 * 'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => nil
5192 *
5193 * Related: see {Querying}[rdoc-ref:String@Querying].
5194 */
5195
5196static VALUE
5197rb_str_match_m(int argc, VALUE *argv, VALUE str)
5198{
5199 VALUE re, result;
5200 if (argc < 1)
5201 rb_check_arity(argc, 1, 2);
5202 re = argv[0];
5203 argv[0] = str;
5204 result = rb_funcallv(get_pat(re), rb_intern("match"), argc, argv);
5205 if (!NIL_P(result) && rb_block_given_p()) {
5206 return rb_yield(result);
5207 }
5208 return result;
5209}
5210
5211/*
5212 * call-seq:
5213 * match?(pattern, offset = 0) -> true or false
5214 *
5215 * Returns whether a match is found for +self+ and the given arguments;
5216 * does not update {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5217 *
5218 * Computes +regexp+ by converting +pattern+ (if not already a Regexp):
5219 *
5220 * regexp = Regexp.new(pattern)
5221 *
5222 * The search for +regexp+ in +self+ begins at the given character +offset+.
5223 * Returns +true+ if a match is found, +false+ otherwise:
5224 *
5225 * 'foo'.match?(/o/) # => true
5226 * 'foo'.match?('o') # => true
5227 * 'foo'.match?(/x/) # => false
5228 * 'foo'.match?('f', 1) # => false
5229 * 'foo'.match?('o', 1) # => true
5230 *
5231 * Related: see {Querying}[rdoc-ref:String@Querying].
5232 */
5233
5234static VALUE
5235rb_str_match_m_p(int argc, VALUE *argv, VALUE str)
5236{
5237 VALUE re;
5238 rb_check_arity(argc, 1, 2);
5239 re = get_pat(argv[0]);
5240 return rb_reg_match_p(re, str, argc > 1 ? NUM2LONG(argv[1]) : 0);
5241}
5242
5243enum neighbor_char {
5244 NEIGHBOR_NOT_CHAR,
5245 NEIGHBOR_FOUND,
5246 NEIGHBOR_WRAPPED
5247};
5248
5249static enum neighbor_char
5250enc_succ_char(char *p, long len, rb_encoding *enc)
5251{
5252 long i;
5253 int l;
5254
5255 if (rb_enc_mbminlen(enc) > 1) {
5256 /* wchar, trivial case */
5257 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5258 if (!MBCLEN_CHARFOUND_P(r)) {
5259 return NEIGHBOR_NOT_CHAR;
5260 }
5261 c = rb_enc_mbc_to_codepoint(p, p + len, enc) + 1;
5262 l = rb_enc_code_to_mbclen(c, enc);
5263 if (!l) return NEIGHBOR_NOT_CHAR;
5264 if (l != len) return NEIGHBOR_WRAPPED;
5265 rb_enc_mbcput(c, p, enc);
5266 r = rb_enc_precise_mbclen(p, p + len, enc);
5267 if (!MBCLEN_CHARFOUND_P(r)) {
5268 return NEIGHBOR_NOT_CHAR;
5269 }
5270 return NEIGHBOR_FOUND;
5271 }
5272 while (1) {
5273 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0xff; i--)
5274 p[i] = '\0';
5275 if (i < 0)
5276 return NEIGHBOR_WRAPPED;
5277 ++((unsigned char*)p)[i];
5278 l = rb_enc_precise_mbclen(p, p+len, enc);
5279 if (MBCLEN_CHARFOUND_P(l)) {
5280 l = MBCLEN_CHARFOUND_LEN(l);
5281 if (l == len) {
5282 return NEIGHBOR_FOUND;
5283 }
5284 else {
5285 memset(p+l, 0xff, len-l);
5286 }
5287 }
5288 if (MBCLEN_INVALID_P(l) && i < len-1) {
5289 long len2;
5290 int l2;
5291 for (len2 = len-1; 0 < len2; len2--) {
5292 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5293 if (!MBCLEN_INVALID_P(l2))
5294 break;
5295 }
5296 memset(p+len2+1, 0xff, len-(len2+1));
5297 }
5298 }
5299}
5300
5301static enum neighbor_char
5302enc_pred_char(char *p, long len, rb_encoding *enc)
5303{
5304 long i;
5305 int l;
5306 if (rb_enc_mbminlen(enc) > 1) {
5307 /* wchar, trivial case */
5308 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5309 if (!MBCLEN_CHARFOUND_P(r)) {
5310 return NEIGHBOR_NOT_CHAR;
5311 }
5312 c = rb_enc_mbc_to_codepoint(p, p + len, enc);
5313 if (!c) return NEIGHBOR_NOT_CHAR;
5314 --c;
5315 l = rb_enc_code_to_mbclen(c, enc);
5316 if (!l) return NEIGHBOR_NOT_CHAR;
5317 if (l != len) return NEIGHBOR_WRAPPED;
5318 rb_enc_mbcput(c, p, enc);
5319 r = rb_enc_precise_mbclen(p, p + len, enc);
5320 if (!MBCLEN_CHARFOUND_P(r)) {
5321 return NEIGHBOR_NOT_CHAR;
5322 }
5323 return NEIGHBOR_FOUND;
5324 }
5325 while (1) {
5326 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0; i--)
5327 p[i] = '\xff';
5328 if (i < 0)
5329 return NEIGHBOR_WRAPPED;
5330 --((unsigned char*)p)[i];
5331 l = rb_enc_precise_mbclen(p, p+len, enc);
5332 if (MBCLEN_CHARFOUND_P(l)) {
5333 l = MBCLEN_CHARFOUND_LEN(l);
5334 if (l == len) {
5335 return NEIGHBOR_FOUND;
5336 }
5337 else {
5338 memset(p+l, 0, len-l);
5339 }
5340 }
5341 if (MBCLEN_INVALID_P(l) && i < len-1) {
5342 long len2;
5343 int l2;
5344 for (len2 = len-1; 0 < len2; len2--) {
5345 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5346 if (!MBCLEN_INVALID_P(l2))
5347 break;
5348 }
5349 memset(p+len2+1, 0, len-(len2+1));
5350 }
5351 }
5352}
5353
5354/*
5355 overwrite +p+ by succeeding letter in +enc+ and returns
5356 NEIGHBOR_FOUND or NEIGHBOR_WRAPPED.
5357 When NEIGHBOR_WRAPPED, carried-out letter is stored into carry.
5358 assuming each ranges are successive, and mbclen
5359 never change in each ranges.
5360 NEIGHBOR_NOT_CHAR is returned if invalid character or the range has only one
5361 character.
5362 */
5363static enum neighbor_char
5364enc_succ_alnum_char(char *p, long len, rb_encoding *enc, char *carry)
5365{
5366 enum neighbor_char ret;
5367 unsigned int c;
5368 int ctype;
5369 int range;
5370 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5371
5372 /* skip 03A2, invalid char between GREEK CAPITAL LETTERS */
5373 int try;
5374 const int max_gaps = 1;
5375
5376 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5377 if (rb_enc_isctype(c, ONIGENC_CTYPE_DIGIT, enc))
5378 ctype = ONIGENC_CTYPE_DIGIT;
5379 else if (rb_enc_isctype(c, ONIGENC_CTYPE_ALPHA, enc))
5380 ctype = ONIGENC_CTYPE_ALPHA;
5381 else
5382 return NEIGHBOR_NOT_CHAR;
5383
5384 MEMCPY(save, p, char, len);
5385 for (try = 0; try <= max_gaps; ++try) {
5386 ret = enc_succ_char(p, len, enc);
5387 if (ret == NEIGHBOR_FOUND) {
5388 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5389 if (rb_enc_isctype(c, ctype, enc))
5390 return NEIGHBOR_FOUND;
5391 }
5392 }
5393 MEMCPY(p, save, char, len);
5394 range = 1;
5395 while (1) {
5396 MEMCPY(save, p, char, len);
5397 ret = enc_pred_char(p, len, enc);
5398 if (ret == NEIGHBOR_FOUND) {
5399 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5400 if (!rb_enc_isctype(c, ctype, enc)) {
5401 MEMCPY(p, save, char, len);
5402 break;
5403 }
5404 }
5405 else {
5406 MEMCPY(p, save, char, len);
5407 break;
5408 }
5409 range++;
5410 }
5411 if (range == 1) {
5412 return NEIGHBOR_NOT_CHAR;
5413 }
5414
5415 if (ctype != ONIGENC_CTYPE_DIGIT) {
5416 MEMCPY(carry, p, char, len);
5417 return NEIGHBOR_WRAPPED;
5418 }
5419
5420 MEMCPY(carry, p, char, len);
5421 enc_succ_char(carry, len, enc);
5422 return NEIGHBOR_WRAPPED;
5423}
5424
5425
5426static VALUE str_succ(VALUE str);
5427
5428/*
5429 * call-seq:
5430 * succ -> new_str
5431 *
5432 * :include: doc/string/succ.rdoc
5433 *
5434 */
5435
5436VALUE
5438{
5439 VALUE str;
5440 str = rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5441 rb_enc_cr_str_copy_for_substr(str, orig);
5442 return str_succ(str);
5443}
5444
5445static VALUE
5446str_succ(VALUE str)
5447{
5448 rb_encoding *enc;
5449 char *sbeg, *s, *e, *last_alnum = 0;
5450 int found_alnum = 0;
5451 long l, slen;
5452 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] = "\1";
5453 long carry_pos = 0, carry_len = 1;
5454 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5455
5456 slen = RSTRING_LEN(str);
5457 if (slen == 0) return str;
5458
5459 enc = STR_ENC_GET(str);
5460 sbeg = RSTRING_PTR(str);
5461 s = e = sbeg + slen;
5462
5463 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5464 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5465 if (ISALPHA(*last_alnum) ? ISDIGIT(*s) :
5466 ISDIGIT(*last_alnum) ? ISALPHA(*s) : 0) {
5467 break;
5468 }
5469 }
5470 l = rb_enc_precise_mbclen(s, e, enc);
5471 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5472 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5473 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5474 switch (neighbor) {
5475 case NEIGHBOR_NOT_CHAR:
5476 continue;
5477 case NEIGHBOR_FOUND:
5478 return str;
5479 case NEIGHBOR_WRAPPED:
5480 last_alnum = s;
5481 break;
5482 }
5483 found_alnum = 1;
5484 carry_pos = s - sbeg;
5485 carry_len = l;
5486 }
5487 if (!found_alnum) { /* str contains no alnum */
5488 s = e;
5489 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5490 enum neighbor_char neighbor;
5491 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5492 l = rb_enc_precise_mbclen(s, e, enc);
5493 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5494 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5495 MEMCPY(tmp, s, char, l);
5496 neighbor = enc_succ_char(tmp, l, enc);
5497 switch (neighbor) {
5498 case NEIGHBOR_FOUND:
5499 MEMCPY(s, tmp, char, l);
5500 return str;
5501 break;
5502 case NEIGHBOR_WRAPPED:
5503 MEMCPY(s, tmp, char, l);
5504 break;
5505 case NEIGHBOR_NOT_CHAR:
5506 break;
5507 }
5508 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5509 /* wrapped to \0...\0. search next valid char. */
5510 enc_succ_char(s, l, enc);
5511 }
5512 if (!rb_enc_asciicompat(enc)) {
5513 MEMCPY(carry, s, char, l);
5514 carry_len = l;
5515 }
5516 carry_pos = s - sbeg;
5517 }
5519 }
5520 RESIZE_CAPA(str, slen + carry_len);
5521 sbeg = RSTRING_PTR(str);
5522 s = sbeg + carry_pos;
5523 memmove(s + carry_len, s, slen - carry_pos);
5524 memmove(s, carry, carry_len);
5525 slen += carry_len;
5526 STR_SET_LEN(str, slen);
5527 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5528 rb_enc_str_coderange(str);
5529 return str;
5530}
5531
5532
5533/*
5534 * call-seq:
5535 * succ! -> self
5536 *
5537 * Like String#succ, but modifies +self+ in place; returns +self+.
5538 *
5539 * Related: see {Modifying}[rdoc-ref:String@Modifying].
5540 */
5541
5542static VALUE
5543rb_str_succ_bang(VALUE str)
5544{
5545 rb_str_modify(str);
5546 str_succ(str);
5547 return str;
5548}
5549
5550static int
5551all_digits_p(const char *s, long len)
5552{
5553 while (len-- > 0) {
5554 if (!ISDIGIT(*s)) return 0;
5555 s++;
5556 }
5557 return 1;
5558}
5559
5560static int
5561str_upto_i(VALUE str, VALUE arg)
5562{
5563 rb_yield(str);
5564 return 0;
5565}
5566
5567/*
5568 * call-seq:
5569 * upto(other_string, exclusive = false) {|string| ... } -> self
5570 * upto(other_string, exclusive = false) -> new_enumerator
5571 *
5572 * :include: doc/string/upto.rdoc
5573 *
5574 */
5575
5576static VALUE
5577rb_str_upto(int argc, VALUE *argv, VALUE beg)
5578{
5579 VALUE end, exclusive;
5580
5581 rb_scan_args(argc, argv, "11", &end, &exclusive);
5582 RETURN_ENUMERATOR(beg, argc, argv);
5583 return rb_str_upto_each(beg, end, RTEST(exclusive), str_upto_i, Qnil);
5584}
5585
5586VALUE
5587rb_str_upto_each(VALUE beg, VALUE end, int excl, int (*each)(VALUE, VALUE), VALUE arg)
5588{
5589 VALUE current, after_end;
5590 ID succ;
5591 int n, ascii;
5592 rb_encoding *enc;
5593
5594 CONST_ID(succ, "succ");
5595 StringValue(end);
5596 enc = rb_enc_check(beg, end);
5597 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5598 /* single character */
5599 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5600 char c = RSTRING_PTR(beg)[0];
5601 char e = RSTRING_PTR(end)[0];
5602
5603 if (c > e || (excl && c == e)) return beg;
5604 for (;;) {
5605 VALUE str = rb_enc_str_new(&c, 1, enc);
5607 if ((*each)(str, arg)) break;
5608 if (!excl && c == e) break;
5609 c++;
5610 if (excl && c == e) break;
5611 }
5612 return beg;
5613 }
5614 /* both edges are all digits */
5615 if (ascii && ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
5616 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5617 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5618 VALUE b, e;
5619 int width;
5620
5621 width = RSTRING_LENINT(beg);
5622 b = rb_str_to_inum(beg, 10, FALSE);
5623 e = rb_str_to_inum(end, 10, FALSE);
5624 if (FIXNUM_P(b) && FIXNUM_P(e)) {
5625 long bi = FIX2LONG(b);
5626 long ei = FIX2LONG(e);
5627 rb_encoding *usascii = rb_usascii_encoding();
5628
5629 while (bi <= ei) {
5630 if (excl && bi == ei) break;
5631 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5632 bi++;
5633 }
5634 }
5635 else {
5636 ID op = excl ? '<' : idLE;
5637 VALUE args[2], fmt = rb_fstring_lit("%.*d");
5638
5639 args[0] = INT2FIX(width);
5640 while (rb_funcall(b, op, 1, e)) {
5641 args[1] = b;
5642 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5643 b = rb_funcallv(b, succ, 0, 0);
5644 }
5645 }
5646 return beg;
5647 }
5648 /* normal case */
5649 n = rb_str_cmp(beg, end);
5650 if (n > 0 || (excl && n == 0)) return beg;
5651
5652 after_end = rb_funcallv(end, succ, 0, 0);
5653 current = str_duplicate(rb_cString, beg);
5654 while (!rb_str_equal(current, after_end)) {
5655 VALUE next = Qnil;
5656 if (excl || !rb_str_equal(current, end))
5657 next = rb_funcallv(current, succ, 0, 0);
5658 if ((*each)(current, arg)) break;
5659 if (NIL_P(next)) break;
5660 current = next;
5661 StringValue(current);
5662 if (excl && rb_str_equal(current, end)) break;
5663 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5664 break;
5665 }
5666
5667 return beg;
5668}
5669
5670VALUE
5671rb_str_upto_endless_each(VALUE beg, int (*each)(VALUE, VALUE), VALUE arg)
5672{
5673 VALUE current;
5674 ID succ;
5675
5676 CONST_ID(succ, "succ");
5677 /* both edges are all digits */
5678 if (is_ascii_string(beg) && ISDIGIT(RSTRING_PTR(beg)[0]) &&
5679 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5680 VALUE b, args[2], fmt = rb_fstring_lit("%.*d");
5681 int width = RSTRING_LENINT(beg);
5682 b = rb_str_to_inum(beg, 10, FALSE);
5683 if (FIXNUM_P(b)) {
5684 long bi = FIX2LONG(b);
5685 rb_encoding *usascii = rb_usascii_encoding();
5686
5687 while (FIXABLE(bi)) {
5688 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5689 bi++;
5690 }
5691 b = LONG2NUM(bi);
5692 }
5693 args[0] = INT2FIX(width);
5694 while (1) {
5695 args[1] = b;
5696 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5697 b = rb_funcallv(b, succ, 0, 0);
5698 }
5699 }
5700 /* normal case */
5701 current = str_duplicate(rb_cString, beg);
5702 while (1) {
5703 VALUE next = rb_funcallv(current, succ, 0, 0);
5704 if ((*each)(current, arg)) break;
5705 current = next;
5706 StringValue(current);
5707 if (RSTRING_LEN(current) == 0)
5708 break;
5709 }
5710
5711 return beg;
5712}
5713
5714static int
5715include_range_i(VALUE str, VALUE arg)
5716{
5717 VALUE *argp = (VALUE *)arg;
5718 if (!rb_equal(str, *argp)) return 0;
5719 *argp = Qnil;
5720 return 1;
5721}
5722
5723VALUE
5724rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive)
5725{
5726 beg = rb_str_new_frozen(beg);
5727 StringValue(end);
5728 end = rb_str_new_frozen(end);
5729 if (NIL_P(val)) return Qfalse;
5730 val = rb_check_string_type(val);
5731 if (NIL_P(val)) return Qfalse;
5732 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5733 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5734 rb_enc_asciicompat(STR_ENC_GET(val))) {
5735 const char *bp = RSTRING_PTR(beg);
5736 const char *ep = RSTRING_PTR(end);
5737 const char *vp = RSTRING_PTR(val);
5738 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5739 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5740 return Qfalse;
5741 else {
5742 char b = *bp;
5743 char e = *ep;
5744 char v = *vp;
5745
5746 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
5747 if (b <= v && v < e) return Qtrue;
5748 return RBOOL(!RTEST(exclusive) && v == e);
5749 }
5750 }
5751 }
5752#if 0
5753 /* both edges are all digits */
5754 if (ISDIGIT(*bp) && ISDIGIT(*ep) &&
5755 all_digits_p(bp, RSTRING_LEN(beg)) &&
5756 all_digits_p(ep, RSTRING_LEN(end))) {
5757 /* TODO */
5758 }
5759#endif
5760 }
5761 rb_str_upto_each(beg, end, RTEST(exclusive), include_range_i, (VALUE)&val);
5762
5763 return RBOOL(NIL_P(val));
5764}
5765
5766static VALUE
5767rb_str_subpat(VALUE str, VALUE re, VALUE backref)
5768{
5769 if (rb_reg_search(re, str, 0, 0) >= 0) {
5770 VALUE match = rb_backref_get();
5771 int nth = rb_reg_backref_number(match, backref);
5772 return rb_reg_nth_match(nth, match);
5773 }
5774 return Qnil;
5775}
5776
5777static VALUE
5778rb_str_aref(VALUE str, VALUE indx)
5779{
5780 long idx;
5781
5782 if (FIXNUM_P(indx)) {
5783 idx = FIX2LONG(indx);
5784 }
5785 else if (RB_TYPE_P(indx, T_REGEXP)) {
5786 return rb_str_subpat(str, indx, INT2FIX(0));
5787 }
5788 else if (RB_TYPE_P(indx, T_STRING)) {
5789 if (rb_str_index(str, indx, 0) != -1)
5790 return str_duplicate(rb_cString, indx);
5791 return Qnil;
5792 }
5793 else {
5794 /* check if indx is Range */
5795 long beg, len = str_strlen(str, NULL);
5796 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
5797 case Qfalse:
5798 break;
5799 case Qnil:
5800 return Qnil;
5801 default:
5802 return rb_str_substr(str, beg, len);
5803 }
5804 idx = NUM2LONG(indx);
5805 }
5806
5807 return str_substr(str, idx, 1, FALSE);
5808}
5809
5810
5811/*
5812 * call-seq:
5813 * self[offset] -> new_string or nil
5814 * self[offset, size] -> new_string or nil
5815 * self[range] -> new_string or nil
5816 * self[regexp, capture = 0] -> new_string or nil
5817 * self[substring] -> new_string or nil
5818 *
5819 * :include: doc/string/aref.rdoc
5820 *
5821 */
5822
5823static VALUE
5824rb_str_aref_m(int argc, VALUE *argv, VALUE str)
5825{
5826 if (argc == 2) {
5827 if (RB_TYPE_P(argv[0], T_REGEXP)) {
5828 return rb_str_subpat(str, argv[0], argv[1]);
5829 }
5830 else {
5831 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5832 }
5833 }
5834 rb_check_arity(argc, 1, 2);
5835 return rb_str_aref(str, argv[0]);
5836}
5837
5838VALUE
5840{
5841 char *ptr = RSTRING_PTR(str);
5842 long olen = RSTRING_LEN(str), nlen;
5843
5844 str_modifiable(str);
5845 if (len > olen) len = olen;
5846 nlen = olen - len;
5847 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5848 char *oldptr = ptr;
5849 size_t old_capa = RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5850 int fl = (int)(RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5851 STR_SET_EMBED(str);
5852 ptr = RSTRING(str)->as.embed.ary;
5853 memmove(ptr, oldptr + len, nlen);
5854 if (fl == STR_NOEMBED) {
5855 SIZED_FREE_N(oldptr, old_capa);
5856 }
5857 }
5858 else {
5859 if (!STR_SHARED_P(str)) {
5860 VALUE shared = heap_str_make_shared(rb_obj_class(str), str);
5861 rb_enc_cr_str_exact_copy(shared, str);
5863 }
5864 ptr = RSTRING(str)->as.heap.ptr += len;
5865 }
5866 STR_SET_LEN(str, nlen);
5867
5868 if (!SHARABLE_MIDDLE_SUBSTRING) {
5869 TERM_FILL(ptr + nlen, TERM_LEN(str));
5870 }
5872 return str;
5873}
5874
5875static void
5876rb_str_update_1(VALUE str, long beg, long len, VALUE val, long vbeg, long vlen)
5877{
5878 char *sptr;
5879 long slen;
5880 int cr;
5881
5882 if (beg == 0 && vlen == 0) {
5883 rb_str_drop_bytes(str, len);
5884 return;
5885 }
5886
5887 str_modify_keep_cr(str);
5888 RSTRING_GETMEM(str, sptr, slen);
5889 if (len < vlen) {
5890 /* expand string */
5891 RESIZE_CAPA(str, slen + vlen - len);
5892 sptr = RSTRING_PTR(str);
5893 }
5894
5896 cr = rb_enc_str_coderange(val);
5897 else
5899
5900 if (vlen != len) {
5901 memmove(sptr + beg + vlen,
5902 sptr + beg + len,
5903 slen - (beg + len));
5904 }
5905 if (vlen < beg && len < 0) {
5906 MEMZERO(sptr + slen, char, -len);
5907 }
5908 if (vlen > 0) {
5909 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5910 }
5911 slen += vlen - len;
5912 STR_SET_LEN(str, slen);
5913 TERM_FILL(&sptr[slen], TERM_LEN(str));
5914 ENC_CODERANGE_SET(str, cr);
5915}
5916
5917static inline void
5918rb_str_update_0(VALUE str, long beg, long len, VALUE val)
5919{
5920 rb_str_update_1(str, beg, len, val, 0, RSTRING_LEN(val));
5921}
5922
5923void
5924rb_str_update(VALUE str, long beg, long len, VALUE val)
5925{
5926 long slen;
5927 char *p, *e;
5928 rb_encoding *enc;
5929 int singlebyte = single_byte_optimizable(str);
5930 int cr;
5931
5932 if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
5933
5934 StringValue(val);
5935 enc = rb_enc_check(str, val);
5936 slen = str_strlen(str, enc); /* rb_enc_check */
5937
5938 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5939 rb_raise(rb_eIndexError, "index %ld out of string", beg);
5940 }
5941 if (beg < 0) {
5942 beg += slen;
5943 }
5944 RUBY_ASSERT(beg >= 0);
5945 RUBY_ASSERT(beg <= slen);
5946
5947 if (len > slen - beg) {
5948 len = slen - beg;
5949 }
5950 p = str_nth(RSTRING_PTR(str), RSTRING_END(str), beg, enc, singlebyte);
5951 if (!p) p = RSTRING_END(str);
5952 e = str_nth(p, RSTRING_END(str), len, enc, singlebyte);
5953 if (!e) e = RSTRING_END(str);
5954 /* error check */
5955 beg = p - RSTRING_PTR(str); /* physical position */
5956 len = e - p; /* physical length */
5957 rb_str_update_0(str, beg, len, val);
5958 rb_enc_associate(str, enc);
5960 if (cr != ENC_CODERANGE_BROKEN)
5961 ENC_CODERANGE_SET(str, cr);
5962}
5963
5964static void
5965rb_str_subpat_set(VALUE str, VALUE re, VALUE backref, VALUE val)
5966{
5967 int nth;
5968 VALUE match;
5969 long start, end, len;
5970 rb_encoding *enc;
5971
5972 if (rb_reg_search(re, str, 0, 0) < 0) {
5973 rb_raise(rb_eIndexError, "regexp not matched");
5974 }
5975 match = rb_backref_get();
5976 nth = rb_reg_backref_number(match, backref);
5977 int num_regs = RMATCH_NREGS(match);
5978 if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
5979 rb_raise(rb_eIndexError, "index %d out of regexp", nth);
5980 }
5981 if (nth < 0) {
5982 nth += num_regs;
5983 }
5984
5985 start = RMATCH_BEG(match, nth);
5986 if (start == -1) {
5987 rb_raise(rb_eIndexError, "regexp group %d not matched", nth);
5988 }
5989 end = RMATCH_END(match, nth);
5990 len = end - start;
5991 StringValue(val);
5992 enc = rb_enc_check_str(str, val);
5993 rb_str_update_0(str, start, len, val);
5994 rb_enc_associate(str, enc);
5995}
5996
5997static VALUE
5998rb_str_aset(VALUE str, VALUE indx, VALUE val)
5999{
6000 long idx, beg;
6001
6002 switch (TYPE(indx)) {
6003 case T_REGEXP:
6004 rb_str_subpat_set(str, indx, INT2FIX(0), val);
6005 return val;
6006
6007 case T_STRING:
6008 beg = rb_str_index(str, indx, 0);
6009 if (beg < 0) {
6010 rb_raise(rb_eIndexError, "string not matched");
6011 }
6012 beg = rb_str_sublen(str, beg);
6013 rb_str_update(str, beg, str_strlen(indx, NULL), val);
6014 return val;
6015
6016 default:
6017 /* check if indx is Range */
6018 {
6019 long beg, len;
6020 if (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 2)) {
6021 rb_str_update(str, beg, len, val);
6022 return val;
6023 }
6024 }
6025 /* FALLTHROUGH */
6026
6027 case T_FIXNUM:
6028 idx = NUM2LONG(indx);
6029 rb_str_update(str, idx, 1, val);
6030 return val;
6031 }
6032}
6033
6034/*
6035 * call-seq:
6036 * self[index] = other_string -> new_string
6037 * self[start, length] = other_string -> new_string
6038 * self[range] = other_string -> new_string
6039 * self[regexp, capture = 0] = other_string -> new_string
6040 * self[substring] = other_string -> new_string
6041 *
6042 * :include: doc/string/aset.rdoc
6043 *
6044 */
6045
6046static VALUE
6047rb_str_aset_m(int argc, VALUE *argv, VALUE str)
6048{
6049 if (argc == 3) {
6050 if (RB_TYPE_P(argv[0], T_REGEXP)) {
6051 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6052 }
6053 else {
6054 rb_str_update(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
6055 }
6056 return argv[2];
6057 }
6058 rb_check_arity(argc, 2, 3);
6059 return rb_str_aset(str, argv[0], argv[1]);
6060}
6061
6062/*
6063 * call-seq:
6064 * insert(offset, other_string) -> self
6065 *
6066 * :include: doc/string/insert.rdoc
6067 *
6068 */
6069
6070static VALUE
6071rb_str_insert(VALUE str, VALUE idx, VALUE str2)
6072{
6073 long pos = NUM2LONG(idx);
6074
6075 if (pos == -1) {
6076 return rb_str_append(str, str2);
6077 }
6078 else if (pos < 0) {
6079 pos++;
6080 }
6081 rb_str_update(str, pos, 0, str2);
6082 return str;
6083}
6084
6085
6086/*
6087 * call-seq:
6088 * slice!(index) -> new_string or nil
6089 * slice!(start, length) -> new_string or nil
6090 * slice!(range) -> new_string or nil
6091 * slice!(regexp, capture = 0) -> new_string or nil
6092 * slice!(substring) -> new_string or nil
6093 *
6094 * Like String#[] (and its alias String#slice), except that:
6095 *
6096 * - Performs substitutions in +self+ (not in a copy of +self+).
6097 * - Returns the removed substring if any modifications were made, +nil+ otherwise.
6098 *
6099 * A few examples:
6100 *
6101 * s = 'hello'
6102 * s.slice!('e') # => "e"
6103 * s # => "hllo"
6104 * s.slice!('e') # => nil
6105 * s # => "hllo"
6106 *
6107 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6108 */
6109
6110static VALUE
6111rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
6112{
6113 VALUE result = Qnil;
6114 VALUE indx;
6115 long beg, len = 1;
6116 char *p;
6117
6118 rb_check_arity(argc, 1, 2);
6119 str_modify_keep_cr(str);
6120 indx = argv[0];
6121 if (RB_TYPE_P(indx, T_REGEXP)) {
6122 if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
6123 VALUE match = rb_backref_get();
6124 int num_regs = RMATCH_NREGS(match);
6125 int nth = 0;
6126 if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
6127 if ((nth += num_regs) <= 0) return Qnil;
6128 }
6129 else if (nth >= num_regs) return Qnil;
6130 beg = RMATCH_BEG(match, nth);
6131 len = RMATCH_END(match, nth) - beg;
6132 goto subseq;
6133 }
6134 else if (argc == 2) {
6135 beg = NUM2LONG(indx);
6136 len = NUM2LONG(argv[1]);
6137 goto num_index;
6138 }
6139 else if (FIXNUM_P(indx)) {
6140 beg = FIX2LONG(indx);
6141 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6142 if (!len) return Qnil;
6143 beg = p - RSTRING_PTR(str);
6144 goto subseq;
6145 }
6146 else if (RB_TYPE_P(indx, T_STRING)) {
6147 beg = rb_str_index(str, indx, 0);
6148 if (beg == -1) return Qnil;
6149 len = RSTRING_LEN(indx);
6150 result = str_duplicate(rb_cString, indx);
6151 goto squash;
6152 }
6153 else {
6154 switch (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 0)) {
6155 case Qnil:
6156 return Qnil;
6157 case Qfalse:
6158 beg = NUM2LONG(indx);
6159 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6160 if (!len) return Qnil;
6161 beg = p - RSTRING_PTR(str);
6162 goto subseq;
6163 default:
6164 goto num_index;
6165 }
6166 }
6167
6168 num_index:
6169 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6170 beg = p - RSTRING_PTR(str);
6171
6172 subseq:
6173 result = rb_str_new(RSTRING_PTR(str)+beg, len);
6174 rb_enc_cr_str_copy_for_substr(result, str);
6175
6176 squash:
6177 if (len > 0) {
6178 if (beg == 0) {
6179 rb_str_drop_bytes(str, len);
6180 }
6181 else {
6182 char *sptr = RSTRING_PTR(str);
6183 long slen = RSTRING_LEN(str);
6184 if (beg + len > slen) /* pathological check */
6185 len = slen - beg;
6186 memmove(sptr + beg,
6187 sptr + beg + len,
6188 slen - (beg + len));
6189 slen -= len;
6190 STR_SET_LEN(str, slen);
6191 TERM_FILL(&sptr[slen], TERM_LEN(str));
6192 }
6193 }
6194 return result;
6195}
6196
6197static VALUE
6198get_pat(VALUE pat)
6199{
6200 VALUE val;
6201
6202 switch (OBJ_BUILTIN_TYPE(pat)) {
6203 case T_REGEXP:
6204 return pat;
6205
6206 case T_STRING:
6207 break;
6208
6209 default:
6210 val = rb_check_string_type(pat);
6211 if (NIL_P(val)) {
6212 Check_Type(pat, T_REGEXP);
6213 }
6214 pat = val;
6215 }
6216
6217 return rb_reg_regcomp(pat);
6218}
6219
6220static VALUE
6221get_pat_quoted(VALUE pat, int check)
6222{
6223 VALUE val;
6224
6225 switch (OBJ_BUILTIN_TYPE(pat)) {
6226 case T_REGEXP:
6227 return pat;
6228
6229 case T_STRING:
6230 break;
6231
6232 default:
6233 val = rb_check_string_type(pat);
6234 if (NIL_P(val)) {
6235 Check_Type(pat, T_REGEXP);
6236 }
6237 pat = val;
6238 }
6239 if (check && is_broken_string(pat)) {
6240 rb_exc_raise(rb_reg_check_preprocess(pat));
6241 }
6242 return pat;
6243}
6244
6245static long
6246rb_pat_search0(VALUE pat, VALUE str, long pos, int set_backref_str, VALUE *match)
6247{
6248 if (BUILTIN_TYPE(pat) == T_STRING) {
6249 pos = rb_str_byteindex(str, pat, pos);
6250 if (set_backref_str) {
6251 if (pos >= 0) {
6252 str = rb_str_new_frozen_String(str);
6253 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6254 if (match) {
6255 *match = match_data;
6256 }
6257 }
6258 else {
6260 }
6261 }
6262 return pos;
6263 }
6264 else {
6265 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6266 }
6267}
6268
6269static long
6270rb_pat_search(VALUE pat, VALUE str, long pos, int set_backref_str)
6271{
6272 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6273}
6274
6275
6276/*
6277 * call-seq:
6278 * sub!(pattern, replacement) -> self or nil
6279 * sub!(pattern) {|match| ... } -> self or nil
6280 *
6281 * Like String#sub, except that:
6282 *
6283 * - Changes are made to +self+, not to copy of +self+.
6284 * - Returns +self+ if any changes are made, +nil+ otherwise.
6285 *
6286 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6287 */
6288
6289static VALUE
6290rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
6291{
6292 VALUE pat, repl, hash = Qnil;
6293 int iter = 0;
6294 long plen;
6295 int min_arity = rb_block_given_p() ? 1 : 2;
6296 long beg;
6297
6298 rb_check_arity(argc, min_arity, 2);
6299 if (argc == 1) {
6300 iter = 1;
6301 }
6302 else {
6303 repl = argv[1];
6304 if (!RB_TYPE_P(repl, T_STRING)) {
6305 hash = rb_check_hash_type(repl);
6306 if (NIL_P(hash)) {
6307 StringValue(repl);
6308 }
6309 }
6310 }
6311
6312 pat = get_pat_quoted(argv[0], 1);
6313
6314 str_modifiable(str);
6315 beg = rb_pat_search(pat, str, 0, 1);
6316 if (beg >= 0) {
6317 rb_encoding *enc;
6318 int cr = ENC_CODERANGE(str);
6319 long beg0, end0;
6320 VALUE match, match0 = Qnil;
6321 char *p, *rp;
6322 long len, rlen;
6323
6324 match = rb_backref_get();
6325 if (RB_TYPE_P(pat, T_STRING)) {
6326 beg0 = beg;
6327 end0 = beg0 + RSTRING_LEN(pat);
6328 match0 = pat;
6329 }
6330 else {
6331 beg0 = RMATCH_BEG(match, 0);
6332 end0 = RMATCH_END(match, 0);
6333 if (iter) match0 = rb_reg_nth_match(0, match);
6334 }
6335
6336 if (iter || !NIL_P(hash)) {
6337 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6338
6339 if (iter) {
6340 repl = rb_obj_as_string(rb_yield(match0));
6341 }
6342 else {
6343 repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0));
6344 repl = rb_obj_as_string(repl);
6345 }
6346 str_mod_check(str, p, len);
6347 rb_check_frozen(str);
6348 }
6349 else {
6350 repl = rb_reg_regsub_match(repl, str, match);
6351 }
6352
6353 enc = rb_enc_compatible(str, repl);
6354 if (!enc) {
6355 rb_encoding *str_enc = STR_ENC_GET(str);
6356 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6357 if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
6358 coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
6359 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
6360 rb_enc_inspect_name(str_enc),
6361 rb_enc_inspect_name(STR_ENC_GET(repl)));
6362 }
6363 enc = STR_ENC_GET(repl);
6364 }
6365 rb_str_modify(str);
6366 rb_enc_associate(str, enc);
6368 int cr2 = ENC_CODERANGE(repl);
6369 if (cr2 == ENC_CODERANGE_BROKEN ||
6370 (cr == ENC_CODERANGE_VALID && cr2 == ENC_CODERANGE_7BIT))
6372 else
6373 cr = cr2;
6374 }
6375 plen = end0 - beg0;
6376 rlen = RSTRING_LEN(repl);
6377 len = RSTRING_LEN(str);
6378 if (rlen > plen) {
6379 RESIZE_CAPA(str, len + rlen - plen);
6380 }
6381 p = RSTRING_PTR(str);
6382 if (rlen != plen) {
6383 memmove(p + beg0 + rlen, p + beg0 + plen, len - beg0 - plen);
6384 }
6385 rp = RSTRING_PTR(repl);
6386 memmove(p + beg0, rp, rlen);
6387 len += rlen - plen;
6388 STR_SET_LEN(str, len);
6389 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
6390 ENC_CODERANGE_SET(str, cr);
6391
6392 RB_GC_GUARD(match);
6393
6394 return str;
6395 }
6396 return Qnil;
6397}
6398
6399
6400/*
6401 * call-seq:
6402 * sub(pattern, replacement) -> new_string
6403 * sub(pattern) {|match| ... } -> new_string
6404 *
6405 * :include: doc/string/sub.rdoc
6406 */
6407
6408static VALUE
6409rb_str_sub(int argc, VALUE *argv, VALUE str)
6410{
6411 str = str_duplicate(rb_cString, str);
6412 rb_str_sub_bang(argc, argv, str);
6413 return str;
6414}
6415
6416static VALUE
6417str_gsub(int argc, VALUE *argv, VALUE str, int bang)
6418{
6419 VALUE pat, val = Qnil, repl, match0 = Qnil, dest, hash = Qnil, match = Qnil;
6420 long beg, beg0, end0;
6421 long offset, blen, slen, len, last;
6422 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6423 char *sp, *cp;
6424 int need_backref_str = -1;
6425 rb_encoding *str_enc;
6426
6427 switch (argc) {
6428 case 1:
6429 RETURN_ENUMERATOR(str, argc, argv);
6430 mode = ITER;
6431 break;
6432 case 2:
6433 repl = argv[1];
6434 if (!RB_TYPE_P(repl, T_STRING)) {
6435 hash = rb_check_hash_type(repl);
6436 if (NIL_P(hash)) {
6437 StringValue(repl);
6438 }
6439 else if (rb_hash_default_unredefined(hash) && !FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6440 mode = FAST_MAP;
6441 }
6442 else {
6443 mode = MAP;
6444 }
6445 }
6446 break;
6447 default:
6448 rb_error_arity(argc, 1, 2);
6449 }
6450
6451 pat = get_pat_quoted(argv[0], 1);
6452 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6453
6454 if (beg < 0) {
6455 if (bang) return Qnil; /* no match, no substitution */
6456 return str_duplicate(rb_cString, str);
6457 }
6458 if (bang) str_modify_keep_cr(str);
6459
6460 offset = 0;
6461 blen = RSTRING_LEN(str) + 30; /* len + margin */
6462 dest = rb_str_buf_new(blen);
6463 sp = RSTRING_PTR(str);
6464 slen = RSTRING_LEN(str);
6465 cp = sp;
6466 str_enc = STR_ENC_GET(str);
6467 rb_enc_associate(dest, str_enc);
6468 ENC_CODERANGE_SET(dest, rb_enc_asciicompat(str_enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
6469
6470 do {
6471 if (RB_TYPE_P(pat, T_STRING)) {
6472 beg0 = beg;
6473 end0 = beg0 + RSTRING_LEN(pat);
6474 match0 = pat;
6475 }
6476 else {
6477 beg0 = RMATCH_BEG(match, 0);
6478 end0 = RMATCH_END(match, 0);
6479 if (mode == ITER) match0 = rb_reg_nth_match(0, match);
6480 }
6481
6482 if (mode != STR) {
6483 if (mode == ITER) {
6484 val = rb_obj_as_string(rb_yield(match0));
6485 }
6486 else {
6487 struct RString fake_str = {RBASIC_INIT};
6488 VALUE key;
6489 if (mode == FAST_MAP) {
6490 // It is safe to use a fake_str here because we established that it won't escape,
6491 // as it's only used for `rb_hash_aref` and we checked the hash doesn't have a
6492 // default proc.
6493 key = setup_fake_str(&fake_str, sp + beg0, end0 - beg0, ENCODING_GET_INLINED(str));
6494 }
6495 else {
6496 key = rb_str_subseq(str, beg0, end0 - beg0);
6497 }
6498 val = rb_hash_aref(hash, key);
6499 val = rb_obj_as_string(val);
6500 }
6501 str_mod_check(str, sp, slen);
6502 if (val == dest) { /* paranoid check [ruby-dev:24827] */
6503 rb_raise(rb_eRuntimeError, "block should not cheat");
6504 }
6505 }
6506 else if (need_backref_str) {
6507 val = rb_reg_regsub_match(repl, str, match);
6508 if (need_backref_str < 0) {
6509 need_backref_str = val != repl;
6510 }
6511 }
6512 else {
6513 val = repl;
6514 }
6515
6516 len = beg0 - offset; /* copy pre-match substr */
6517 if (len) {
6518 rb_enc_str_buf_cat(dest, cp, len, str_enc);
6519 }
6520
6521 rb_str_buf_append(dest, val);
6522
6523 last = offset;
6524 offset = end0;
6525 if (beg0 == end0) {
6526 /*
6527 * Always consume at least one character of the input string
6528 * in order to prevent infinite loops.
6529 */
6530 if (RSTRING_LEN(str) <= end0) break;
6531 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0, RSTRING_END(str), str_enc);
6532 rb_enc_str_buf_cat(dest, RSTRING_PTR(str)+end0, len, str_enc);
6533 offset = end0 + len;
6534 }
6535 cp = RSTRING_PTR(str) + offset;
6536 if (offset > RSTRING_LEN(str)) break;
6537
6538 // In FAST_MAP and STR mode the backref can't escape so we can re-use the MatchData safely.
6539 if (mode != FAST_MAP && mode != STR) {
6540 match = Qnil;
6541 }
6542 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6543
6544 RB_GC_GUARD(match);
6545 } while (beg >= 0);
6546
6547 if (RSTRING_LEN(str) > offset) {
6548 rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
6549 }
6550 rb_pat_search0(pat, str, last, 1, &match);
6551 if (bang) {
6552 str_shared_replace(str, dest);
6553 }
6554 else {
6555 str = dest;
6556 }
6557
6558 return str;
6559}
6560
6561
6562/*
6563 * call-seq:
6564 * gsub!(pattern, replacement) -> self or nil
6565 * gsub!(pattern) {|match| ... } -> self or nil
6566 * gsub!(pattern) -> an_enumerator
6567 *
6568 * Like String#gsub, except that:
6569 *
6570 * - Performs substitutions in +self+ (not in a copy of +self+).
6571 * - Returns +self+ if any substitutions were performed, +nil+ otherwise.
6572 *
6573 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6574 */
6575
6576static VALUE
6577rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
6578{
6579 str_modifiable(str);
6580 return str_gsub(argc, argv, str, 1);
6581}
6582
6583
6584/*
6585 * call-seq:
6586 * gsub(pattern, replacement) -> new_string
6587 * gsub(pattern) {|match| ... } -> new_string
6588 * gsub(pattern) -> enumerator
6589 *
6590 * Returns a copy of +self+ with zero or more substrings replaced.
6591 *
6592 * Argument +pattern+ may be a string or a Regexp;
6593 * argument +replacement+ may be a string or a Hash.
6594 * Varying types for the argument values makes this method very versatile.
6595 *
6596 * Below are some simple examples;
6597 * for many more examples, see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
6598 *
6599 * With arguments +pattern+ and string +replacement+ given,
6600 * replaces each matching substring with the given +replacement+ string:
6601 *
6602 * s = 'abracadabra'
6603 * s.gsub('ab', 'AB') # => "ABracadABra"
6604 * s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
6605 *
6606 * With arguments +pattern+ and hash +replacement+ given,
6607 * replaces each matching substring with a value from the given +replacement+ hash,
6608 * or removes it:
6609 *
6610 * h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
6611 * s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
6612 * s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
6613 *
6614 * With argument +pattern+ and a block given,
6615 * calls the block with each matching substring;
6616 * replaces that substring with the block's return value:
6617 *
6618 * s.gsub(/[a-d]/) {|substring| substring.upcase }
6619 * # => "ABrACADABrA"
6620 *
6621 * With argument +pattern+ and no block given,
6622 * returns a new Enumerator.
6623 *
6624 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
6625 */
6626
6627static VALUE
6628rb_str_gsub(int argc, VALUE *argv, VALUE str)
6629{
6630 return str_gsub(argc, argv, str, 0);
6631}
6632
6633
6634/*
6635 * call-seq:
6636 * replace(other_string) -> self
6637 *
6638 * Replaces the contents of +self+ with the contents of +other_string+;
6639 * returns +self+:
6640 *
6641 * s = 'foo' # => "foo"
6642 * s.replace('bar') # => "bar"
6643 *
6644 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6645 */
6646
6647VALUE
6649{
6650 str_modifiable(str);
6651 if (str == str2) return str;
6652
6653 StringValue(str2);
6654 str_discard(str);
6655 return str_replace(str, str2);
6656}
6657
6658/*
6659 * call-seq:
6660 * clear -> self
6661 *
6662 * Removes the contents of +self+:
6663 *
6664 * s = 'foo'
6665 * s.clear # => ""
6666 * s # => ""
6667 *
6668 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6669 */
6670
6671static VALUE
6672rb_str_clear(VALUE str)
6673{
6674 str_discard(str);
6675 STR_SET_EMBED(str);
6676 STR_SET_LEN(str, 0);
6677 RSTRING_PTR(str)[0] = 0;
6678 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6680 else
6682 return str;
6683}
6684
6685/*
6686 * call-seq:
6687 * chr -> string
6688 *
6689 * :include: doc/string/chr.rdoc
6690 *
6691 */
6692
6693static VALUE
6694rb_str_chr(VALUE str)
6695{
6696 return rb_str_substr(str, 0, 1);
6697}
6698
6699/*
6700 * call-seq:
6701 * getbyte(index) -> integer or nil
6702 *
6703 * :include: doc/string/getbyte.rdoc
6704 *
6705 */
6706VALUE
6707rb_str_getbyte(VALUE str, VALUE index)
6708{
6709 long pos = NUM2LONG(index);
6710
6711 if (pos < 0)
6712 pos += RSTRING_LEN(str);
6713 if (pos < 0 || RSTRING_LEN(str) <= pos)
6714 return Qnil;
6715
6716 return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
6717}
6718
6719/*
6720 * call-seq:
6721 * setbyte(index, integer) -> integer
6722 *
6723 * Sets the byte at zero-based offset +index+ to the value of the given +integer+;
6724 * returns +integer+:
6725 *
6726 * s = 'xyzzy'
6727 * s.setbyte(2, 129) # => 129
6728 * s # => "xy\x81zy"
6729 *
6730 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6731 */
6732VALUE
6733rb_str_setbyte(VALUE str, VALUE index, VALUE value)
6734{
6735 long pos = NUM2LONG(index);
6736 long len = RSTRING_LEN(str);
6737 char *ptr, *head, *left = 0;
6738 rb_encoding *enc;
6739 int cr = ENC_CODERANGE_UNKNOWN, width, nlen;
6740
6741 if (pos < -len || len <= pos)
6742 rb_raise(rb_eIndexError, "index %ld out of string", pos);
6743 if (pos < 0)
6744 pos += len;
6745
6746 VALUE v = rb_to_int(value);
6747 VALUE w = rb_int_and(v, INT2FIX(0xff));
6748 char byte = (char)(NUM2INT(w) & 0xFF);
6749
6750 if (!str_independent(str))
6751 str_make_independent(str);
6752 enc = STR_ENC_GET(str);
6753 head = RSTRING_PTR(str);
6754 ptr = &head[pos];
6755 if (!STR_EMBED_P(str)) {
6756 cr = ENC_CODERANGE(str);
6757 switch (cr) {
6758 case ENC_CODERANGE_7BIT:
6759 left = ptr;
6760 *ptr = byte;
6761 if (ISASCII(byte)) goto end;
6762 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6763 if (!MBCLEN_CHARFOUND_P(nlen))
6765 else
6767 goto end;
6769 left = rb_enc_left_char_head(head, ptr, head+len, enc);
6770 width = rb_enc_precise_mbclen(left, head+len, enc);
6771 *ptr = byte;
6772 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6773 if (!MBCLEN_CHARFOUND_P(nlen))
6775 else if (MBCLEN_CHARFOUND_LEN(nlen) != width || ISASCII(byte))
6777 goto end;
6778 }
6779 }
6781 *ptr = byte;
6782
6783 end:
6784 return value;
6785}
6786
6787static inline bool
6788str_bit_offset_out_of_range(long byte_len, uint64_t bit_offset)
6789{
6790 /* Compare byte indexes to avoid overflowing byte_len * CHAR_BIT. */
6791 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6792}
6793
6794/*
6795 * Keep both the full bit offset and its long representation. Most calls use a
6796 * Fixnum-sized offset and can stay on the original long fast path; only large
6797 * Bignum offsets need the uint64_t path below. This matters on platforms
6798 * where long is narrower than the address space, such as 32-bit and LLP64.
6799 */
6801 uint64_t value;
6802 long long_value;
6803 bool fits_long;
6804};
6805
6806static inline struct str_bit_offset
6807str_bit_offset_from_index(VALUE index)
6808{
6809 VALUE integer = rb_to_int(index);
6810 struct str_bit_offset offset;
6811
6812 /*
6813 * FIXNUM_P only decides whether the common long path is immediately usable.
6814 * This covers practically all offsets on LP64 platforms; Bignum offsets
6815 * are still accepted below when they fit in uint64_t, mainly for platforms
6816 * with 32-bit long where large strings can have Bignum bit offsets.
6817 */
6818 if (FIXNUM_P(integer)) {
6819 offset.long_value = FIX2LONG(integer);
6820 if (offset.long_value < 0) {
6821 rb_raise(rb_eIndexError, "bit index out of range");
6822 }
6823 offset.value = (uint64_t)offset.long_value;
6824 offset.fits_long = true;
6825 return offset;
6826 }
6827
6828 RUBY_ASSERT(RB_TYPE_P(integer, T_BIGNUM));
6829 if (rb_int_negative_p(integer)) {
6830 rb_raise(rb_eIndexError, "bit index out of range");
6831 }
6832 if (rb_cmpint(rb_int_cmp(integer, ULL2NUM(UINT64_MAX)), integer, ULL2NUM(UINT64_MAX)) > 0) {
6833 rb_raise(rb_eArgError, "bit index out of representable range");
6834 }
6835
6836 offset.value = (uint64_t)NUM2ULL(integer);
6837 if (offset.value <= (uint64_t)LONG_MAX) {
6838 offset.long_value = (long)offset.value;
6839 offset.fits_long = true;
6840 }
6841 else {
6842 offset.long_value = 0;
6843 offset.fits_long = false;
6844 }
6845 return offset;
6846}
6847
6848static bool
6849str_lsb_first(int argc, VALUE *argv, VALUE *index)
6850{
6851 static ID keywords[1];
6852 VALUE opts, vlsb_first;
6853
6854 if (!keywords[0]) {
6855 keywords[0] = rb_intern_const("lsb_first");
6856 }
6857
6858 rb_scan_args(argc, argv, "1:", index, &opts);
6859 rb_get_kwargs(opts, keywords, 0, 1, &vlsb_first);
6860 if (vlsb_first == Qundef || vlsb_first == Qtrue) {
6861 return true;
6862 }
6863 if (vlsb_first == Qfalse) {
6864 return false;
6865 }
6866 rb_raise(rb_eArgError, "lsb_first must be true or false");
6867 UNREACHABLE_RETURN(false);
6868}
6869
6870static inline uint64_t
6871str_logical_to_physical_bit64(uint64_t logical, bool lsb_first)
6872{
6873 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
6874}
6875
6876static inline long
6877str_logical_to_physical_bit(long logical, bool lsb_first)
6878{
6879 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
6880}
6881
6883 long byte_index;
6884 unsigned int bit_offset;
6885};
6886
6887static inline struct str_bit_location
6888str_bit_location_from_offset(uint64_t logical, bool lsb_first)
6889{
6890 /*
6891 * When long is 32-bit, a bit offset for a large string can be a Bignum
6892 * while the byte index still fits in long, which is RSTRING_LEN's type.
6893 */
6894 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
6895 struct str_bit_location location;
6896 location.byte_index = (long)(physical / CHAR_BIT);
6897 location.bit_offset = (unsigned int)(physical % CHAR_BIT);
6898 return location;
6899}
6900
6901static inline int
6902str_get_bit(const char *ptr, long bit_index)
6903{
6904 return (((unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
6905}
6906
6907static inline int
6908str_get_bit_location(const char *ptr, struct str_bit_location location)
6909{
6910 return (((unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
6911}
6912
6913static int
6914str_bit_get(int argc, VALUE *argv, VALUE str)
6915{
6916 VALUE index;
6917 bool lsb_first = str_lsb_first(argc, argv, &index);
6918 struct str_bit_offset offset = str_bit_offset_from_index(index);
6919
6920 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
6921 return -1;
6922 }
6923
6924 if (offset.fits_long) {
6925 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.long_value, lsb_first));
6926 }
6927 else {
6928 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
6929 }
6930}
6931
6932/*
6933 * call-seq:
6934 * bit_get(offset, lsb_first: true) -> 0, 1, or nil
6935 *
6936 * :include: doc/string/bit_get.rdoc
6937 *
6938 */
6939static VALUE
6940rb_str_bit_get(int argc, VALUE *argv, VALUE str)
6941{
6942 int bit = str_bit_get(argc, argv, str);
6943 return bit < 0 ? Qnil : INT2FIX(bit);
6944}
6945
6946/*
6947 * call-seq:
6948 * bit_set?(offset, lsb_first: true) -> true, false, or nil
6949 *
6950 * :include: doc/string/bit_set_p.rdoc
6951 *
6952 */
6953static VALUE
6954rb_str_bit_set_p(int argc, VALUE *argv, VALUE str)
6955{
6956 int bit = str_bit_get(argc, argv, str);
6957 return bit < 0 ? Qnil : RBOOL(bit);
6958}
6959
6960enum str_bit_mutation {
6961 STR_BIT_SET,
6962 STR_BIT_CLEAR,
6963 STR_BIT_FLIP
6964};
6965
6966static VALUE
6967str_mutate_bit(int argc, VALUE *argv, VALUE str, enum str_bit_mutation mutation)
6968{
6969 VALUE index;
6970 bool lsb_first = str_lsb_first(argc, argv, &index);
6971 struct str_bit_offset offset = str_bit_offset_from_index(index);
6972 struct str_bit_location location;
6973 long bit_index;
6974 unsigned char *ptr;
6975 unsigned char mask;
6976
6977 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
6978 rb_raise(rb_eIndexError, "bit index out of range");
6979 }
6980
6981 rb_str_modify(str);
6982 ptr = (unsigned char *)RSTRING_PTR(str);
6983 if (offset.fits_long) {
6984 bit_index = str_logical_to_physical_bit(offset.long_value, lsb_first);
6985 mask = (unsigned char)(1u << (bit_index % CHAR_BIT));
6986 location.byte_index = bit_index / CHAR_BIT;
6987 }
6988 else {
6989 location = str_bit_location_from_offset(offset.value, lsb_first);
6990 mask = (unsigned char)(1u << location.bit_offset);
6991 }
6992
6993 switch (mutation) {
6994 case STR_BIT_SET:
6995 ptr[location.byte_index] |= mask;
6996 break;
6997 case STR_BIT_CLEAR:
6998 ptr[location.byte_index] &= (unsigned char)~mask;
6999 break;
7000 case STR_BIT_FLIP:
7001 ptr[location.byte_index] ^= mask;
7002 break;
7003 }
7004
7005 return str;
7006}
7007
7008/*
7009 * call-seq:
7010 * bit_set(offset, lsb_first: true) -> self
7011 *
7012 * :include: doc/string/bit_set.rdoc
7013 *
7014 */
7015static VALUE
7016rb_str_bit_set(int argc, VALUE *argv, VALUE str)
7017{
7018 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7019}
7020
7021/*
7022 * call-seq:
7023 * bit_clear(offset, lsb_first: true) -> self
7024 *
7025 * :include: doc/string/bit_clear.rdoc
7026 *
7027 */
7028static VALUE
7029rb_str_bit_clear(int argc, VALUE *argv, VALUE str)
7030{
7031 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7032}
7033
7034/*
7035 * call-seq:
7036 * bit_flip(offset, lsb_first: true) -> self
7037 *
7038 * :include: doc/string/bit_flip.rdoc
7039 *
7040 */
7041static VALUE
7042rb_str_bit_flip(int argc, VALUE *argv, VALUE str)
7043{
7044 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7045}
7046
7047static uint64_t
7048str_count_bits(const unsigned char *ptr, long len)
7049{
7050 uint64_t count = 0;
7051 long off = 0;
7052 long unrolled_end = len & ~31L;
7053 long aligned_end = len & ~7L;
7054
7055 // 32 bytes (256 bits) at a time
7056 for (; off < unrolled_end; off += 32) {
7057 uint64_t w0, w1, w2, w3;
7058 memcpy(&w0, ptr + off, 8);
7059 memcpy(&w1, ptr + off + 8, 8);
7060 memcpy(&w2, ptr + off + 16, 8);
7061 memcpy(&w3, ptr + off + 24, 8);
7062 count += rb_popcount64(w0);
7063 count += rb_popcount64(w1);
7064 count += rb_popcount64(w2);
7065 count += rb_popcount64(w3);
7066 }
7067
7068 // 8 bytes (64 bits) at a time
7069 for (; off < aligned_end; off += 8) {
7070 uint64_t word;
7071 memcpy(&word, ptr + off, 8);
7072 count += rb_popcount64(word);
7073 }
7074
7075 // remaining bytes
7076 if (off < len) {
7077 uint64_t word = 0;
7078 int shift = 0;
7079 for (; off < len; off++, shift += CHAR_BIT) {
7080 word |= (uint64_t)ptr[off] << shift;
7081 }
7082 count += rb_popcount64(word);
7083 }
7084
7085 return count;
7086}
7087
7088/*
7089 * call-seq:
7090 * bit_count -> integer
7091 *
7092 * :include: doc/string/bit_count.rdoc
7093 *
7094 */
7095static VALUE
7096rb_str_bit_count(VALUE str)
7097{
7098 return ULL2NUM(str_count_bits((const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7099}
7100
7101static void
7102str_check_bitwise_length(VALUE str, VALUE other)
7103{
7104 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7105 rb_raise(rb_eArgError, "operands must have the same length (%ld vs %ld)",
7106 RSTRING_LEN(str), RSTRING_LEN(other));
7107 }
7108}
7109
7110static VALUE
7111str_bitwise_result(VALUE str)
7112{
7113 long len = RSTRING_LEN(str);
7114 VALUE result = rb_str_buf_new(len);
7115 rb_str_resize(result, len);
7116 rb_enc_associate(result, rb_ascii8bit_encoding());
7117 ENC_CODERANGE_CLEAR(result);
7118 return result;
7119}
7120
7121#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7122 static void \
7123 name(unsigned char *dst, const unsigned char *src, long len) \
7124 { \
7125 long off = 0; \
7126 long unrolled_end = len & ~31L; \
7127 long aligned_end = len & ~7L; \
7128 for (; off < unrolled_end; off += 32) { \
7129 uint64_t s0, s1, s2, s3; \
7130 memcpy(&s0, src + off, 8); \
7131 memcpy(&s1, src + off + 8, 8); \
7132 memcpy(&s2, src + off + 16, 8); \
7133 memcpy(&s3, src + off + 24, 8); \
7134 s0 = (expr_word(s0)); \
7135 s1 = (expr_word(s1)); \
7136 s2 = (expr_word(s2)); \
7137 s3 = (expr_word(s3)); \
7138 memcpy(dst + off, &s0, 8); \
7139 memcpy(dst + off + 8, &s1, 8); \
7140 memcpy(dst + off + 16, &s2, 8); \
7141 memcpy(dst + off + 24, &s3, 8); \
7142 } \
7143 for (; off < aligned_end; off += 8) { \
7144 uint64_t word; \
7145 memcpy(&word, src + off, 8); \
7146 word = (expr_word(word)); \
7147 memcpy(dst + off, &word, 8); \
7148 } \
7149 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7150 }
7151
7152#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7153 static void \
7154 name(unsigned char *dst, const unsigned char *lhs, \
7155 const unsigned char *rhs, long len) \
7156 { \
7157 long off = 0; \
7158 long unrolled_end = len & ~31L; \
7159 long aligned_end = len & ~7L; \
7160 for (; off < unrolled_end; off += 32) { \
7161 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7162 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7163 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7164 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7165 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7166 l0 = expr_word(l0, r0); \
7167 l1 = expr_word(l1, r1); \
7168 l2 = expr_word(l2, r2); \
7169 l3 = expr_word(l3, r3); \
7170 memcpy(dst + off, &l0, 8); \
7171 memcpy(dst + off + 8, &l1, 8); \
7172 memcpy(dst + off + 16, &l2, 8); \
7173 memcpy(dst + off + 24, &l3, 8); \
7174 } \
7175 for (; off < aligned_end; off += 8) { \
7176 uint64_t lhs_word, rhs_word; \
7177 memcpy(&lhs_word, lhs + off, 8); \
7178 memcpy(&rhs_word, rhs + off, 8); \
7179 lhs_word = expr_word(lhs_word, rhs_word); \
7180 memcpy(dst + off, &lhs_word, 8); \
7181 } \
7182 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7183 }
7184
7185#define STR_BITWISE_NOT_WORD(x) (~(x))
7186#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7187#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7188#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7189#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7190#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7191#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7192#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7193
7194STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7195STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7196STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7197STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7198
7199/*
7200 * call-seq:
7201 * bitwise_not -> string
7202 *
7203 * :include: doc/string/bitwise_not.rdoc
7204 *
7205 */
7206static VALUE
7207rb_str_bitwise_not(VALUE str)
7208{
7209 long len = RSTRING_LEN(str);
7210 VALUE result = str_bitwise_result(str);
7211 str_bitwise_not((unsigned char *)RSTRING_PTR(result),
7212 (const unsigned char *)RSTRING_PTR(str), len);
7213 return result;
7214}
7215
7216/*
7217 * call-seq:
7218 * bitwise_not! -> self
7219 *
7220 * :include: doc/string/bitwise_not_bang.rdoc
7221 *
7222 */
7223static VALUE
7224rb_str_bitwise_not_bang(VALUE str)
7225{
7226 long len;
7227 unsigned char *ptr;
7228
7229 rb_str_modify(str);
7230 len = RSTRING_LEN(str);
7231 ptr = (unsigned char *)RSTRING_PTR(str);
7232 str_bitwise_not(ptr, ptr, len);
7233 return str;
7234}
7235
7236#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7237 static VALUE \
7238 rb_str_bitwise_##name(VALUE str, VALUE other) \
7239 { \
7240 long len; \
7241 VALUE result; \
7242 StringValue(other); \
7243 str_check_bitwise_length(str, other); \
7244 len = RSTRING_LEN(str); \
7245 result = str_bitwise_result(str); \
7246 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7247 (const unsigned char *)RSTRING_PTR(str), \
7248 (const unsigned char *)RSTRING_PTR(other), len); \
7249 return result; \
7250 } \
7251 static VALUE \
7252 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7253 { \
7254 long len; \
7255 unsigned char *ptr; \
7256 StringValue(other); \
7257 str_check_bitwise_length(str, other); \
7258 rb_str_modify(str); \
7259 len = RSTRING_LEN(str); \
7260 ptr = (unsigned char *)RSTRING_PTR(str); \
7261 str_bitwise_##name(ptr, ptr, \
7262 (const unsigned char *)RSTRING_PTR(other), len); \
7263 return str; \
7264 }
7265
7266STR_DEFINE_BINARY_BITWISE_METHOD(and)
7267STR_DEFINE_BINARY_BITWISE_METHOD(or)
7268STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7269
7270static VALUE
7271str_byte_substr(VALUE str, long beg, long len, int empty)
7272{
7273 long n = RSTRING_LEN(str);
7274
7275 if (beg > n || len < 0) return Qnil;
7276 if (beg < 0) {
7277 beg += n;
7278 if (beg < 0) return Qnil;
7279 }
7280 if (len > n - beg)
7281 len = n - beg;
7282 if (len <= 0) {
7283 if (!empty) return Qnil;
7284 len = 0;
7285 }
7286
7287 VALUE str2 = str_subseq(str, beg, len);
7288
7289 str_enc_copy_direct(str2, str);
7290
7291 if (RSTRING_LEN(str2) == 0) {
7292 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7294 else
7296 }
7297 else {
7298 switch (ENC_CODERANGE(str)) {
7299 case ENC_CODERANGE_7BIT:
7301 break;
7302 default:
7304 break;
7305 }
7306 }
7307
7308 return str2;
7309}
7310
7311VALUE
7312rb_str_byte_substr(VALUE str, VALUE beg, VALUE len)
7313{
7314 return str_byte_substr(str, NUM2LONG(beg), NUM2LONG(len), TRUE);
7315}
7316
7317static VALUE
7318str_byte_aref(VALUE str, VALUE indx)
7319{
7320 long idx;
7321 if (FIXNUM_P(indx)) {
7322 idx = FIX2LONG(indx);
7323 }
7324 else {
7325 /* check if indx is Range */
7326 long beg, len = RSTRING_LEN(str);
7327
7328 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
7329 case Qfalse:
7330 break;
7331 case Qnil:
7332 return Qnil;
7333 default:
7334 return str_byte_substr(str, beg, len, TRUE);
7335 }
7336
7337 idx = NUM2LONG(indx);
7338 }
7339 return str_byte_substr(str, idx, 1, FALSE);
7340}
7341
7342/*
7343 * call-seq:
7344 * byteslice(offset, length = 1) -> string or nil
7345 * byteslice(range) -> string or nil
7346 *
7347 * :include: doc/string/byteslice.rdoc
7348 */
7349
7350static VALUE
7351rb_str_byteslice(int argc, VALUE *argv, VALUE str)
7352{
7353 if (argc == 2) {
7354 long beg = NUM2LONG(argv[0]);
7355 long len = NUM2LONG(argv[1]);
7356 return str_byte_substr(str, beg, len, TRUE);
7357 }
7358 rb_check_arity(argc, 1, 2);
7359 return str_byte_aref(str, argv[0]);
7360}
7361
7362static void
7363str_check_beg_len(VALUE str, long *beg, long *len)
7364{
7365 long end, slen = RSTRING_LEN(str);
7366
7367 if (*len < 0) rb_raise(rb_eIndexError, "negative length %ld", *len);
7368 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7369 rb_raise(rb_eIndexError, "index %ld out of string", *beg);
7370 }
7371 if (*beg < 0) {
7372 *beg += slen;
7373 }
7374 RUBY_ASSERT(*beg >= 0);
7375 RUBY_ASSERT(*beg <= slen);
7376
7377 if (*len > slen - *beg) {
7378 *len = slen - *beg;
7379 }
7380 end = *beg + *len;
7381 str_ensure_byte_pos(str, *beg);
7382 str_ensure_byte_pos(str, end);
7383}
7384
7385/*
7386 * call-seq:
7387 * bytesplice(offset, length, str) -> self
7388 * bytesplice(offset, length, str, str_offset, str_length) -> self
7389 * bytesplice(range, str) -> self
7390 * bytesplice(range, str, str_range) -> self
7391 *
7392 * :include: doc/string/bytesplice.rdoc
7393 */
7394
7395static VALUE
7396rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
7397{
7398 long beg, len, vbeg, vlen;
7399 VALUE val;
7400 int cr;
7401
7402 rb_check_arity(argc, 2, 5);
7403 if (!(argc == 2 || argc == 3 || argc == 5)) {
7404 rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7405 }
7406 if (argc == 2 || (argc == 3 && !RB_INTEGER_TYPE_P(argv[0]))) {
7407 if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
7408 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7409 rb_builtin_class_name(argv[0]));
7410 }
7411 val = argv[1];
7412 StringValue(val);
7413 if (argc == 2) {
7414 /* bytesplice(range, str) */
7415 vbeg = 0;
7416 vlen = RSTRING_LEN(val);
7417 }
7418 else {
7419 /* bytesplice(range, str, str_range) */
7420 if (!rb_range_beg_len(argv[2], &vbeg, &vlen, RSTRING_LEN(val), 2)) {
7421 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7422 rb_builtin_class_name(argv[2]));
7423 }
7424 }
7425 }
7426 else {
7427 beg = NUM2LONG(argv[0]);
7428 len = NUM2LONG(argv[1]);
7429 val = argv[2];
7430 StringValue(val);
7431 if (argc == 3) {
7432 /* bytesplice(index, length, str) */
7433 vbeg = 0;
7434 vlen = RSTRING_LEN(val);
7435 }
7436 else {
7437 /* bytesplice(index, length, str, str_index, str_length) */
7438 vbeg = NUM2LONG(argv[3]);
7439 vlen = NUM2LONG(argv[4]);
7440 }
7441 }
7442 str_check_beg_len(str, &beg, &len);
7443 str_check_beg_len(val, &vbeg, &vlen);
7444 str_modify_keep_cr(str);
7445
7446 if (RB_UNLIKELY(ENCODING_GET_INLINED(str) != ENCODING_GET_INLINED(val))) {
7447 rb_enc_associate(str, rb_enc_check(str, val));
7448 }
7449
7450 rb_str_update_1(str, beg, len, val, vbeg, vlen);
7452 if (cr != ENC_CODERANGE_BROKEN)
7453 ENC_CODERANGE_SET(str, cr);
7454 return str;
7455}
7456
7457/*
7458 * call-seq:
7459 * reverse -> new_string
7460 *
7461 * Returns a new string with the characters from +self+ in reverse order.
7462 *
7463 * 'drawer'.reverse # => "reward"
7464 * 'reviled'.reverse # => "deliver"
7465 * 'stressed'.reverse # => "desserts"
7466 * 'semordnilaps'.reverse # => "spalindromes"
7467 *
7468 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7469 */
7470
7471static VALUE
7472rb_str_reverse(VALUE str)
7473{
7474 rb_encoding *enc;
7475 VALUE rev;
7476 char *s, *e, *p;
7477 int cr;
7478
7479 if (RSTRING_LEN(str) <= 1) return str_duplicate(rb_cString, str);
7480 enc = STR_ENC_GET(str);
7481 rev = rb_str_new(0, RSTRING_LEN(str));
7482 s = RSTRING_PTR(str); e = RSTRING_END(str);
7483 p = RSTRING_END(rev);
7484 cr = ENC_CODERANGE(str);
7485
7486 if (RSTRING_LEN(str) > 1) {
7487 if (single_byte_optimizable(str)) {
7488 while (s < e) {
7489 *--p = *s++;
7490 }
7491 }
7492 else if (cr == ENC_CODERANGE_VALID) {
7493 while (s < e) {
7494 int clen = rb_enc_fast_mbclen(s, e, enc);
7495
7496 p -= clen;
7497 memcpy(p, s, clen);
7498 s += clen;
7499 }
7500 }
7501 else {
7502 cr = rb_enc_asciicompat(enc) ?
7504 while (s < e) {
7505 int clen = rb_enc_mbclen(s, e, enc);
7506
7507 if (clen > 1 || (*s & 0x80)) cr = ENC_CODERANGE_UNKNOWN;
7508 p -= clen;
7509 memcpy(p, s, clen);
7510 s += clen;
7511 }
7512 }
7513 }
7514 STR_SET_LEN(rev, RSTRING_LEN(str));
7515 str_enc_copy_direct(rev, str);
7516 ENC_CODERANGE_SET(rev, cr);
7517
7518 return rev;
7519}
7520
7521
7522/*
7523 * call-seq:
7524 * reverse! -> self
7525 *
7526 * Returns +self+ with its characters reversed:
7527 *
7528 * 'drawer'.reverse! # => "reward"
7529 * 'reviled'.reverse! # => "deliver"
7530 * 'stressed'.reverse! # => "desserts"
7531 * 'semordnilaps'.reverse! # => "spalindromes"
7532 *
7533 * Related: see {Modifying}[rdoc-ref:String@Modifying].
7534 */
7535
7536static VALUE
7537rb_str_reverse_bang(VALUE str)
7538{
7539 if (RSTRING_LEN(str) > 1) {
7540 if (single_byte_optimizable(str)) {
7541 char *s, *e, c;
7542
7543 str_modify_keep_cr(str);
7544 s = RSTRING_PTR(str);
7545 e = RSTRING_END(str) - 1;
7546 while (s < e) {
7547 c = *s;
7548 *s++ = *e;
7549 *e-- = c;
7550 }
7551 }
7552 else {
7553 str_shared_replace(str, rb_str_reverse(str));
7554 }
7555 }
7556 else {
7557 str_modify_keep_cr(str);
7558 }
7559 return str;
7560}
7561
7562
7563/*
7564 * call-seq:
7565 * include?(other_string) -> true or false
7566 *
7567 * Returns whether +self+ contains +other_string+:
7568 *
7569 * s = 'bar'
7570 * s.include?('ba') # => true
7571 * s.include?('ar') # => true
7572 * s.include?('bar') # => true
7573 * s.include?('a') # => true
7574 * s.include?('') # => true
7575 * s.include?('foo') # => false
7576 *
7577 * Related: see {Querying}[rdoc-ref:String@Querying].
7578 */
7579
7580VALUE
7581rb_str_include(VALUE str, VALUE arg)
7582{
7583 long i;
7584
7585 StringValue(arg);
7586 i = rb_str_index(str, arg, 0);
7587
7588 return RBOOL(i != -1);
7589}
7590
7591
7592/*
7593 * call-seq:
7594 * to_i(base = 10) -> integer
7595 *
7596 * Returns the result of interpreting leading characters in +self+
7597 * as an integer in the given +base+;
7598 * +base+ must be either +0+ or in range <tt>(2..36)</tt>:
7599 *
7600 * '123456'.to_i # => 123456
7601 * '123def'.to_i(16) # => 1195503
7602 *
7603 * With +base+ zero given, string +object+ may contain leading characters
7604 * to specify the actual base:
7605 *
7606 * '123def'.to_i(0) # => 123
7607 * '0123def'.to_i(0) # => 83
7608 * '0b123def'.to_i(0) # => 1
7609 * '0o123def'.to_i(0) # => 83
7610 * '0d123def'.to_i(0) # => 123
7611 * '0x123def'.to_i(0) # => 1195503
7612 *
7613 * Characters past a leading valid number (in the given +base+) are ignored:
7614 *
7615 * '12.345'.to_i # => 12
7616 * '12345'.to_i(2) # => 1
7617 *
7618 * Returns zero if there is no leading valid number:
7619 *
7620 * 'abcdef'.to_i # => 0
7621 * '2'.to_i(2) # => 0
7622 *
7623 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
7624 */
7625
7626static VALUE
7627rb_str_to_i(int argc, VALUE *argv, VALUE str)
7628{
7629 int base = 10;
7630
7631 if (rb_check_arity(argc, 0, 1) && (base = NUM2INT(argv[0])) < 0) {
7632 rb_raise(rb_eArgError, "invalid radix %d", base);
7633 }
7634 return rb_str_to_inum(str, base, FALSE);
7635}
7636
7637
7638/*
7639 * call-seq:
7640 * to_f -> float
7641 *
7642 * Returns the result of interpreting leading characters in +self+ as a Float:
7643 *
7644 * '3.14159'.to_f # => 3.14159
7645 * '1.234e-2'.to_f # => 0.01234
7646 *
7647 * Characters past a leading valid number are ignored:
7648 *
7649 * '3.14 (pi to two places)'.to_f # => 3.14
7650 *
7651 * Returns zero if there is no leading valid number:
7652 *
7653 * 'abcdef'.to_f # => 0.0
7654 *
7655 * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
7656 */
7657
7658static VALUE
7659rb_str_to_f(VALUE str)
7660{
7661 return DBL2NUM(rb_str_to_dbl(str, FALSE));
7662}
7663
7664
7665/*
7666 * call-seq:
7667 * to_s -> self or new_string
7668 *
7669 * Returns +self+ if +self+ is a +String+,
7670 * or +self+ converted to a +String+ if +self+ is a subclass of +String+.
7671 *
7672 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7673 */
7674
7675static VALUE
7676rb_str_to_s(VALUE str)
7677{
7678 if (rb_obj_class(str) != rb_cString) {
7679 return str_duplicate(rb_cString, str);
7680 }
7681 return str;
7682}
7683
7684#if 0
7685static void
7686str_cat_char(VALUE str, unsigned int c, rb_encoding *enc)
7687{
7688 char s[RUBY_MAX_CHAR_LEN];
7689 int n = rb_enc_codelen(c, enc);
7690
7691 rb_enc_mbcput(c, s, enc);
7692 rb_enc_str_buf_cat(str, s, n, enc);
7693}
7694#endif
7695
7696#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */
7697
7698int
7699rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p)
7700{
7701 char buf[CHAR_ESC_LEN + 1];
7702 int l;
7703
7704#if SIZEOF_INT > 4
7705 c &= 0xffffffff;
7706#endif
7707 if (unicode_p) {
7708 if (c < 0x7F && ISPRINT(c)) {
7709 snprintf(buf, CHAR_ESC_LEN, "%c", c);
7710 }
7711 else if (c < 0x10000) {
7712 snprintf(buf, CHAR_ESC_LEN, "\\u%04X", c);
7713 }
7714 else {
7715 snprintf(buf, CHAR_ESC_LEN, "\\u{%X}", c);
7716 }
7717 }
7718 else {
7719 if (c < 0x100) {
7720 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", c);
7721 }
7722 else {
7723 snprintf(buf, CHAR_ESC_LEN, "\\x{%X}", c);
7724 }
7725 }
7726 l = (int)strlen(buf); /* CHAR_ESC_LEN cannot exceed INT_MAX */
7727 rb_str_buf_cat(result, buf, l);
7728 return l;
7729}
7730
7731const char *
7732ruby_escaped_char(int c)
7733{
7734 switch (c) {
7735 case '\0': return "\\0";
7736 case '\n': return "\\n";
7737 case '\r': return "\\r";
7738 case '\t': return "\\t";
7739 case '\f': return "\\f";
7740 case '\013': return "\\v";
7741 case '\010': return "\\b";
7742 case '\007': return "\\a";
7743 case '\033': return "\\e";
7744 case '\x7f': return "\\c?";
7745 }
7746 return NULL;
7747}
7748
7749VALUE
7750rb_str_escape(VALUE str)
7751{
7752 int encidx = ENCODING_GET(str);
7753 rb_encoding *enc = rb_enc_from_index(encidx);
7754 const char *p = RSTRING_PTR(str);
7755 const char *pend = RSTRING_END(str);
7756 const char *prev = p;
7757 char buf[CHAR_ESC_LEN + 1];
7758 VALUE result = rb_str_buf_new(0);
7759 int unicode_p = rb_enc_unicode_p(enc);
7760 int asciicompat = rb_enc_asciicompat(enc);
7761
7762 while (p < pend) {
7763 unsigned int c;
7764 const char *cc;
7765 int n = rb_enc_precise_mbclen(p, pend, enc);
7766 if (!MBCLEN_CHARFOUND_P(n)) {
7767 if (p > prev) str_buf_cat(result, prev, p - prev);
7768 n = rb_enc_mbminlen(enc);
7769 if (pend < p + n)
7770 n = (int)(pend - p);
7771 while (n--) {
7772 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
7773 str_buf_cat(result, buf, strlen(buf));
7774 prev = ++p;
7775 }
7776 continue;
7777 }
7778 n = MBCLEN_CHARFOUND_LEN(n);
7779 c = rb_enc_mbc_to_codepoint(p, pend, enc);
7780 p += n;
7781 cc = ruby_escaped_char(c);
7782 if (cc) {
7783 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7784 str_buf_cat(result, cc, strlen(cc));
7785 prev = p;
7786 }
7787 else if (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c)) {
7788 }
7789 else {
7790 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7791 rb_str_buf_cat_escaped_char(result, c, unicode_p);
7792 prev = p;
7793 }
7794 }
7795 if (p > prev) str_buf_cat(result, prev, p - prev);
7796 ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
7797
7798 return result;
7799}
7800
7801/* Lookup table for the inspect fast path. 1 marks bytes that need
7802 * no escaping. 0 marks bytes that need escape inspection: 0x00-0x1F
7803 * (control), 0x22 ("), 0x23 (#), 0x5C (\‍), 0x7F (DEL), 0x80-0xFF
7804 * (non-ASCII). */
7805static const bool inspect_no_escape[256] = {
7806 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
7807 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
7808 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20-0x2F */
7809 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30-0x3F */
7810 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F */
7811 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 0x50-0x5F */
7812 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F */
7813 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 0x70-0x7F */
7814};
7815
7816/*
7817 * call-seq:
7818 * inspect -> string
7819 *
7820 * :include: doc/string/inspect.rdoc
7821 *
7822 */
7823
7824VALUE
7826{
7827 int encidx = ENCODING_GET(str);
7828 rb_encoding *enc = rb_enc_from_index(encidx);
7829 const char *p, *pend, *prev;
7830 char buf[CHAR_ESC_LEN + 1];
7831 VALUE result = rb_str_buf_new(RSTRING_LEN(str) + 2); /* string content + surrounding quotes */
7832 rb_encoding *resenc = rb_default_internal_encoding();
7833 int unicode_p = rb_enc_unicode_p(enc);
7834 int asciicompat = rb_enc_asciicompat(enc);
7835 int cr = rb_enc_str_coderange(str);
7836
7837 if (resenc == NULL) resenc = rb_default_external_encoding();
7838 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
7839 rb_enc_associate(result, resenc);
7840 str_buf_cat2(result, "\"");
7841
7842 p = RSTRING_PTR(str); pend = RSTRING_END(str);
7843 prev = p;
7844 while (p < pend) {
7845 unsigned int c, cc;
7846 int n;
7847
7848 /* Fast path: bulk-skip runs of safe ASCII bytes via a lookup table.
7849 * Only well-formed strings (CR=7BIT for any encoding, or UTF-8 VALID)
7850 * are eligible. */
7851 if (cr == ENC_CODERANGE_7BIT ||
7852 (encidx == ENCINDEX_UTF_8 && cr == ENC_CODERANGE_VALID)) {
7853 while (p < pend && inspect_no_escape[(unsigned char)*p]) p++;
7854 if (p >= pend) break;
7855 }
7856
7857 n = rb_enc_precise_mbclen(p, pend, enc);
7858 if (!MBCLEN_CHARFOUND_P(n)) {
7859 if (p > prev) str_buf_cat(result, prev, p - prev);
7860 n = rb_enc_mbminlen(enc);
7861 if (pend < p + n)
7862 n = (int)(pend - p);
7863 while (n--) {
7864 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
7865 str_buf_cat(result, buf, strlen(buf));
7866 prev = ++p;
7867 }
7868 continue;
7869 }
7870 n = MBCLEN_CHARFOUND_LEN(n);
7871 c = rb_enc_mbc_to_codepoint(p, pend, enc);
7872 p += n;
7873 if ((asciicompat || unicode_p) &&
7874 (c == '"'|| c == '\\' ||
7875 (c == '#' &&
7876 p < pend &&
7877 MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
7878 (cc = rb_enc_codepoint(p,pend,enc),
7879 (cc == '$' || cc == '@' || cc == '{'))))) {
7880 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7881 str_buf_cat2(result, "\\");
7882 if (asciicompat || enc == resenc) {
7883 prev = p - n;
7884 continue;
7885 }
7886 }
7887 switch (c) {
7888 case '\n': cc = 'n'; break;
7889 case '\r': cc = 'r'; break;
7890 case '\t': cc = 't'; break;
7891 case '\f': cc = 'f'; break;
7892 case '\013': cc = 'v'; break;
7893 case '\010': cc = 'b'; break;
7894 case '\007': cc = 'a'; break;
7895 case 033: cc = 'e'; break;
7896 default: cc = 0; break;
7897 }
7898 if (cc) {
7899 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7900 buf[0] = '\\';
7901 buf[1] = (char)cc;
7902 str_buf_cat(result, buf, 2);
7903 prev = p;
7904 continue;
7905 }
7906 /* The special casing of 0x85 (NEXT_LINE) here is because
7907 * Oniguruma historically treats it as printable, but it
7908 * doesn't match the print POSIX bracket class or character
7909 * property in regexps.
7910 *
7911 * See Ruby Bug #16842 for details:
7912 * https://bugs.ruby-lang.org/issues/16842
7913 */
7914 if ((enc == resenc && rb_enc_isprint(c, enc) && c != 0x85) ||
7915 (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c))) {
7916 continue;
7917 }
7918 else {
7919 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7920 rb_str_buf_cat_escaped_char(result, c, unicode_p);
7921 prev = p;
7922 continue;
7923 }
7924 }
7925 if (p > prev) str_buf_cat(result, prev, p - prev);
7926 str_buf_cat2(result, "\"");
7927
7928 return result;
7929}
7930
7931#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
7932
7933/*
7934 * call-seq:
7935 * dump -> new_string
7936 *
7937 * :include: doc/string/dump.rdoc
7938 *
7939 */
7940
7941VALUE
7943{
7944 int encidx = rb_enc_get_index(str);
7945 rb_encoding *enc = rb_enc_from_index(encidx);
7946 long len;
7947 const char *p, *pend;
7948 char *q, *qend;
7949 VALUE result;
7950 int u8 = (encidx == rb_utf8_encindex());
7951 static const char nonascii_suffix[] = ".dup.force_encoding(\"%s\")";
7952
7953 len = 2; /* "" */
7954 if (!rb_enc_asciicompat(enc)) {
7955 len += strlen(nonascii_suffix) - rb_strlen_lit("%s");
7956 len += strlen(enc->name);
7957 }
7958
7959 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
7960 while (p < pend) {
7961 int clen;
7962 unsigned char c = *p++;
7963
7964 switch (c) {
7965 case '"': case '\\':
7966 case '\n': case '\r':
7967 case '\t': case '\f':
7968 case '\013': case '\010': case '\007': case '\033':
7969 clen = 2;
7970 break;
7971
7972 case '#':
7973 clen = IS_EVSTR(p, pend) ? 2 : 1;
7974 break;
7975
7976 default:
7977 if (ISPRINT(c)) {
7978 clen = 1;
7979 }
7980 else {
7981 if (u8 && c > 0x7F) { /* \u notation */
7982 int n = rb_enc_precise_mbclen(p-1, pend, enc);
7983 if (MBCLEN_CHARFOUND_P(n)) {
7984 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
7985 if (cc <= 0xFFFF)
7986 clen = 6; /* \uXXXX */
7987 else if (cc <= 0xFFFFF)
7988 clen = 9; /* \u{XXXXX} */
7989 else
7990 clen = 10; /* \u{XXXXXX} */
7991 p += MBCLEN_CHARFOUND_LEN(n)-1;
7992 break;
7993 }
7994 }
7995 clen = 4; /* \xNN */
7996 }
7997 break;
7998 }
7999
8000 if (clen > LONG_MAX - len) {
8001 rb_raise(rb_eRuntimeError, "string size too big");
8002 }
8003 len += clen;
8004 }
8005
8006 result = rb_str_new(0, len);
8007 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8008 q = RSTRING_PTR(result); qend = q + len + 1;
8009
8010 *q++ = '"';
8011 while (p < pend) {
8012 unsigned char c = *p++;
8013
8014 if (c == '"' || c == '\\') {
8015 *q++ = '\\';
8016 *q++ = c;
8017 }
8018 else if (c == '#') {
8019 if (IS_EVSTR(p, pend)) *q++ = '\\';
8020 *q++ = '#';
8021 }
8022 else if (c == '\n') {
8023 *q++ = '\\';
8024 *q++ = 'n';
8025 }
8026 else if (c == '\r') {
8027 *q++ = '\\';
8028 *q++ = 'r';
8029 }
8030 else if (c == '\t') {
8031 *q++ = '\\';
8032 *q++ = 't';
8033 }
8034 else if (c == '\f') {
8035 *q++ = '\\';
8036 *q++ = 'f';
8037 }
8038 else if (c == '\013') {
8039 *q++ = '\\';
8040 *q++ = 'v';
8041 }
8042 else if (c == '\010') {
8043 *q++ = '\\';
8044 *q++ = 'b';
8045 }
8046 else if (c == '\007') {
8047 *q++ = '\\';
8048 *q++ = 'a';
8049 }
8050 else if (c == '\033') {
8051 *q++ = '\\';
8052 *q++ = 'e';
8053 }
8054 else if (ISPRINT(c)) {
8055 *q++ = c;
8056 }
8057 else {
8058 *q++ = '\\';
8059 if (u8) {
8060 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8061 if (MBCLEN_CHARFOUND_P(n)) {
8062 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8063 p += n;
8064 if (cc <= 0xFFFF)
8065 snprintf(q, qend-q, "u%04X", cc); /* \uXXXX */
8066 else
8067 snprintf(q, qend-q, "u{%X}", cc); /* \u{XXXXX} or \u{XXXXXX} */
8068 q += strlen(q);
8069 continue;
8070 }
8071 }
8072 snprintf(q, qend-q, "x%02X", c);
8073 q += 3;
8074 }
8075 }
8076 *q++ = '"';
8077 *q = '\0';
8078 if (!rb_enc_asciicompat(enc)) {
8079 snprintf(q, qend-q, nonascii_suffix, enc->name);
8080 encidx = rb_ascii8bit_encindex();
8081 }
8082 /* result from dump is ASCII */
8083 rb_enc_associate_index(result, encidx);
8085 return result;
8086}
8087
8088static int
8089unescape_ascii(unsigned int c)
8090{
8091 switch (c) {
8092 case 'n':
8093 return '\n';
8094 case 'r':
8095 return '\r';
8096 case 't':
8097 return '\t';
8098 case 'f':
8099 return '\f';
8100 case 'v':
8101 return '\13';
8102 case 'b':
8103 return '\010';
8104 case 'a':
8105 return '\007';
8106 case 'e':
8107 return 033;
8108 }
8110}
8111
8112static void
8113undump_after_backslash(VALUE undumped, const char **ss, const char *s_end, rb_encoding **penc, bool *utf8, bool *binary)
8114{
8115 const char *s = *ss;
8116 unsigned int c;
8117 int codelen;
8118 size_t hexlen;
8119 unsigned char buf[6];
8120 static rb_encoding *enc_utf8 = NULL;
8121
8122 switch (*s) {
8123 case '\\':
8124 case '"':
8125 case '#':
8126 rb_str_cat(undumped, s, 1); /* cat itself */
8127 s++;
8128 break;
8129 case 'n':
8130 case 'r':
8131 case 't':
8132 case 'f':
8133 case 'v':
8134 case 'b':
8135 case 'a':
8136 case 'e':
8137 *buf = unescape_ascii(*s);
8138 rb_str_cat(undumped, (char *)buf, 1);
8139 s++;
8140 break;
8141 case 'u':
8142 if (*binary) {
8143 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8144 }
8145 *utf8 = true;
8146 if (++s >= s_end) {
8147 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8148 }
8149 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8150 if (*penc != enc_utf8) {
8151 *penc = enc_utf8;
8152 rb_enc_associate(undumped, enc_utf8);
8153 }
8154 if (*s == '{') { /* handle \u{...} form */
8155 s++;
8156 for (;;) {
8157 if (s >= s_end) {
8158 rb_raise(rb_eRuntimeError, "unterminated Unicode escape");
8159 }
8160 if (*s == '}') {
8161 s++;
8162 break;
8163 }
8164 if (ISSPACE(*s)) {
8165 s++;
8166 continue;
8167 }
8168 c = scan_hex(s, s_end-s, &hexlen);
8169 if (hexlen == 0 || hexlen > 6) {
8170 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8171 }
8172 if (c > 0x10ffff) {
8173 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint (too large)");
8174 }
8175 if (0xd800 <= c && c <= 0xdfff) {
8176 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8177 }
8178 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8179 rb_str_cat(undumped, (char *)buf, codelen);
8180 s += hexlen;
8181 }
8182 }
8183 else { /* handle \uXXXX form */
8184 c = scan_hex(s, 4, &hexlen);
8185 if (hexlen != 4) {
8186 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8187 }
8188 if (0xd800 <= c && c <= 0xdfff) {
8189 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8190 }
8191 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8192 rb_str_cat(undumped, (char *)buf, codelen);
8193 s += hexlen;
8194 }
8195 break;
8196 case 'x':
8197 if (++s >= s_end) {
8198 rb_raise(rb_eRuntimeError, "invalid hex escape");
8199 }
8200 *buf = scan_hex(s, 2, &hexlen);
8201 if (hexlen != 2) {
8202 rb_raise(rb_eRuntimeError, "invalid hex escape");
8203 }
8204 if (!ISASCII(*buf)) {
8205 if (*utf8) {
8206 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8207 }
8208 *binary = true;
8209 }
8210 rb_str_cat(undumped, (char *)buf, 1);
8211 s += hexlen;
8212 break;
8213 default:
8214 rb_str_cat(undumped, s-1, 2);
8215 s++;
8216 }
8217
8218 *ss = s;
8219}
8220
8221static VALUE rb_str_is_ascii_only_p(VALUE str);
8222
8223/*
8224 * call-seq:
8225 * undump -> new_string
8226 *
8227 * Inverse of String#dump; returns a copy of +self+ with changes of the kinds made by String#dump "undone."
8228 *
8229 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8230 */
8231
8232static VALUE
8233str_undump(VALUE str)
8234{
8235 const char *s = RSTRING_PTR(str);
8236 const char *s_end = RSTRING_END(str);
8237 rb_encoding *enc = rb_enc_get(str);
8238 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8239 bool utf8 = false;
8240 bool binary = false;
8241 int w;
8242
8244 if (rb_str_is_ascii_only_p(str) == Qfalse) {
8245 rb_raise(rb_eRuntimeError, "non-ASCII character detected");
8246 }
8247 if (!str_null_check(str, &w)) {
8248 rb_raise(rb_eRuntimeError, "string contains null byte");
8249 }
8250 if (RSTRING_LEN(str) < 2) goto invalid_format;
8251 if (*s != '"') goto invalid_format;
8252
8253 /* strip '"' at the start */
8254 s++;
8255
8256 for (;;) {
8257 if (s >= s_end) {
8258 rb_raise(rb_eRuntimeError, "unterminated dumped string");
8259 }
8260
8261 if (*s == '"') {
8262 /* epilogue */
8263 s++;
8264 if (s == s_end) {
8265 /* ascii compatible dumped string */
8266 break;
8267 }
8268 else {
8269 static const char force_encoding_suffix[] = ".force_encoding(\""; /* "\")" */
8270 static const char dup_suffix[] = ".dup";
8271 const char *encname;
8272 int encidx;
8273 ptrdiff_t size;
8274
8275 /* check separately for strings dumped by older versions */
8276 size = sizeof(dup_suffix) - 1;
8277 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8278
8279 size = sizeof(force_encoding_suffix) - 1;
8280 if (s_end - s <= size) goto invalid_format;
8281 if (memcmp(s, force_encoding_suffix, size) != 0) goto invalid_format;
8282 s += size;
8283
8284 if (utf8) {
8285 rb_raise(rb_eRuntimeError, "dumped string contained Unicode escape but used force_encoding");
8286 }
8287
8288 encname = s;
8289 s = memchr(s, '"', s_end-s);
8290 size = s - encname;
8291 if (!s) goto invalid_format;
8292 if (s_end - s != 2) goto invalid_format;
8293 if (s[0] != '"' || s[1] != ')') goto invalid_format;
8294
8295 encidx = rb_enc_find_index2(encname, (long)size);
8296 if (encidx < 0) {
8297 rb_raise(rb_eRuntimeError, "dumped string has unknown encoding name");
8298 }
8299 rb_enc_associate_index(undumped, encidx);
8300 }
8301 break;
8302 }
8303
8304 if (*s == '\\') {
8305 s++;
8306 if (s >= s_end) {
8307 rb_raise(rb_eRuntimeError, "invalid escape");
8308 }
8309 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8310 }
8311 else {
8312 rb_str_cat(undumped, s++, 1);
8313 }
8314 }
8315
8316 RB_GC_GUARD(str);
8317
8318 return undumped;
8319invalid_format:
8320 rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8321}
8322
8323static void
8324rb_str_check_dummy_enc(rb_encoding *enc)
8325{
8326 if (rb_enc_dummy_p(enc)) {
8327 rb_raise(rb_eEncCompatError, "incompatible encoding with this operation: %s",
8328 rb_enc_name(enc));
8329 }
8330}
8331
8332static rb_encoding *
8333str_true_enc(VALUE str)
8334{
8335 rb_encoding *enc = STR_ENC_GET(str);
8336 rb_str_check_dummy_enc(enc);
8337 return enc;
8338}
8339
8340static OnigCaseFoldType
8341check_case_options(int argc, VALUE *argv, OnigCaseFoldType flags)
8342{
8343 if (argc==0)
8344 return flags;
8345 if (argc>2)
8346 rb_raise(rb_eArgError, "too many options");
8347 if (argv[0]==sym_turkic) {
8348 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8349 if (argc==2) {
8350 if (argv[1]==sym_lithuanian)
8351 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8352 else
8353 rb_raise(rb_eArgError, "invalid second option");
8354 }
8355 }
8356 else if (argv[0]==sym_lithuanian) {
8357 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8358 if (argc==2) {
8359 if (argv[1]==sym_turkic)
8360 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8361 else
8362 rb_raise(rb_eArgError, "invalid second option");
8363 }
8364 }
8365 else if (argc>1)
8366 rb_raise(rb_eArgError, "too many options");
8367 else if (argv[0]==sym_ascii)
8368 flags |= ONIGENC_CASE_ASCII_ONLY;
8369 else if (argv[0]==sym_fold) {
8370 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8371 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8372 else
8373 rb_raise(rb_eArgError, "option :fold only allowed for downcasing");
8374 }
8375 else
8376 rb_raise(rb_eArgError, "invalid option");
8377 return flags;
8378}
8379
8380static inline bool
8381case_option_single_p(OnigCaseFoldType flags, rb_encoding *enc, VALUE str)
8382{
8383 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() || rb_enc_mbmaxlen(enc) == 1))
8384 return true;
8385 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8386 (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT || rb_is_ascii8bit_enc(enc));
8387}
8388
8389/* 16 should be long enough to absorb any kind of single character length increase */
8390#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8391#ifndef CASEMAP_DEBUG
8392# define CASEMAP_DEBUG 0
8393#endif
8394
8395struct mapping_buffer;
8396typedef struct mapping_buffer {
8397 size_t capa;
8398 size_t used;
8399 struct mapping_buffer *next;
8400 OnigUChar space[FLEX_ARY_LEN];
8402
8403static void
8404mapping_buffer_free(void *p)
8405{
8406 mapping_buffer *previous_buffer;
8407 mapping_buffer *current_buffer = p;
8408 while (current_buffer) {
8409 previous_buffer = current_buffer;
8410 current_buffer = current_buffer->next;
8411 ruby_xfree_sized(previous_buffer, offsetof(mapping_buffer, space) + previous_buffer->capa);
8412 }
8413}
8414
8415static const rb_data_type_t mapping_buffer_type = {
8416 "mapping_buffer",
8417 {0, mapping_buffer_free,},
8418 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8419};
8420
8421static VALUE
8422rb_str_casemap(VALUE source, OnigCaseFoldType *flags, rb_encoding *enc)
8423{
8424 VALUE target;
8425
8426 const OnigUChar *source_current, *source_end;
8427 int target_length = 0;
8428 VALUE buffer_anchor;
8429 mapping_buffer *current_buffer = 0;
8430 mapping_buffer **pre_buffer;
8431 size_t buffer_count = 0;
8432 int buffer_length_or_invalid;
8433
8434 if (RSTRING_LEN(source) == 0) return str_duplicate(rb_cString, source);
8435
8436 source_current = (OnigUChar*)RSTRING_PTR(source);
8437 source_end = (OnigUChar*)RSTRING_END(source);
8438
8439 buffer_anchor = TypedData_Wrap_Struct(0, &mapping_buffer_type, 0);
8440 pre_buffer = (mapping_buffer **)&DATA_PTR(buffer_anchor);
8441 while (source_current < source_end) {
8442 /* increase multiplier using buffer count to converge quickly */
8443 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8444 if (CASEMAP_DEBUG) {
8445 fprintf(stderr, "Buffer allocation, capa is %"PRIuSIZE"\n", capa); /* for tuning */
8446 }
8447 current_buffer = xmalloc(offsetof(mapping_buffer, space) + capa);
8448 *pre_buffer = current_buffer;
8449 pre_buffer = &current_buffer->next;
8450 current_buffer->next = NULL;
8451 current_buffer->capa = capa;
8452 buffer_length_or_invalid = enc->case_map(flags,
8453 &source_current, source_end,
8454 current_buffer->space,
8455 current_buffer->space+current_buffer->capa,
8456 enc);
8457 if (buffer_length_or_invalid < 0) {
8458 current_buffer = DATA_PTR(buffer_anchor);
8459 DATA_PTR(buffer_anchor) = 0;
8460 mapping_buffer_free(current_buffer);
8461 rb_raise(rb_eArgError, "input string invalid");
8462 }
8463 target_length += current_buffer->used = buffer_length_or_invalid;
8464 }
8465 if (CASEMAP_DEBUG) {
8466 fprintf(stderr, "Buffer count is %"PRIuSIZE"\n", buffer_count); /* for tuning */
8467 }
8468
8469 if (buffer_count==1) {
8470 target = rb_str_new((const char*)current_buffer->space, target_length);
8471 }
8472 else {
8473 char *target_current;
8474
8475 target = rb_str_new(0, target_length);
8476 target_current = RSTRING_PTR(target);
8477 current_buffer = DATA_PTR(buffer_anchor);
8478 while (current_buffer) {
8479 memcpy(target_current, current_buffer->space, current_buffer->used);
8480 target_current += current_buffer->used;
8481 current_buffer = current_buffer->next;
8482 }
8483 }
8484 current_buffer = DATA_PTR(buffer_anchor);
8485 DATA_PTR(buffer_anchor) = 0;
8486 mapping_buffer_free(current_buffer);
8487
8488 RB_GC_GUARD(buffer_anchor);
8489
8490 /* TODO: check about string terminator character */
8491 str_enc_copy_direct(target, source);
8492 /*ENC_CODERANGE_SET(mapped, cr);*/
8493
8494 return target;
8495}
8496
8497static VALUE
8498rb_str_ascii_casemap(VALUE source, VALUE target, OnigCaseFoldType *flags, rb_encoding *enc)
8499{
8500 const OnigUChar *source_current, *source_end;
8501 OnigUChar *target_current, *target_end;
8502 long old_length = RSTRING_LEN(source);
8503 int length_or_invalid;
8504
8505 if (old_length == 0) return Qnil;
8506
8507 source_current = (OnigUChar*)RSTRING_PTR(source);
8508 source_end = (OnigUChar*)RSTRING_END(source);
8509 if (source == target) {
8510 target_current = (OnigUChar*)source_current;
8511 target_end = (OnigUChar*)source_end;
8512 }
8513 else {
8514 target_current = (OnigUChar*)RSTRING_PTR(target);
8515 target_end = (OnigUChar*)RSTRING_END(target);
8516 }
8517
8518 length_or_invalid = onigenc_ascii_only_case_map(flags,
8519 &source_current, source_end,
8520 target_current, target_end, enc);
8521 if (length_or_invalid < 0)
8522 rb_raise(rb_eArgError, "input string invalid");
8523 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8524 fprintf(stderr, "problem with rb_str_ascii_casemap"
8525 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8526 rb_raise(rb_eArgError, "internal problem with rb_str_ascii_casemap"
8527 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8528 }
8529
8530 str_enc_copy(target, source);
8531
8532 return target;
8533}
8534
8535static bool
8536upcase_single(VALUE str)
8537{
8538 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8539 bool modified = false;
8540
8541 while (s < send) {
8542 unsigned int c = *(unsigned char*)s;
8543
8544 if ('a' <= c && c <= 'z') {
8545 *s = 'A' + (c - 'a');
8546 modified = true;
8547 }
8548 s++;
8549 }
8550 return modified;
8551}
8552
8553/*
8554 * call-seq:
8555 * upcase!(mapping) -> self or nil
8556 *
8557 * Like String#upcase, except that:
8558 *
8559 * - Changes character casings in +self+ (not in a copy of +self+).
8560 * - Returns +self+ if any changes are made, +nil+ otherwise.
8561 *
8562 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8563 */
8564
8565static VALUE
8566rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
8567{
8568 rb_encoding *enc;
8569 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8570
8571 flags = check_case_options(argc, argv, flags);
8572 str_modify_keep_cr(str);
8573 enc = str_true_enc(str);
8574 if (case_option_single_p(flags, enc, str)) {
8575 if (upcase_single(str))
8576 flags |= ONIGENC_CASE_MODIFIED;
8577 }
8578 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8579 rb_str_ascii_casemap(str, str, &flags, enc);
8580 else
8581 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8582
8583 if (ONIGENC_CASE_MODIFIED&flags) return str;
8584 return Qnil;
8585}
8586
8587
8588/*
8589 * call-seq:
8590 * upcase(mapping = :ascii) -> new_string
8591 *
8592 * :include: doc/string/upcase.rdoc
8593 */
8594
8595static VALUE
8596rb_str_upcase(int argc, VALUE *argv, VALUE str)
8597{
8598 rb_encoding *enc;
8599 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8600 VALUE ret;
8601
8602 flags = check_case_options(argc, argv, flags);
8603 enc = str_true_enc(str);
8604 if (case_option_single_p(flags, enc, str)) {
8605 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8606 str_enc_copy_direct(ret, str);
8607 upcase_single(ret);
8608 }
8609 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8610 ret = rb_str_new(0, RSTRING_LEN(str));
8611 rb_str_ascii_casemap(str, ret, &flags, enc);
8612 }
8613 else {
8614 ret = rb_str_casemap(str, &flags, enc);
8615 }
8616
8617 return ret;
8618}
8619
8620static bool
8621downcase_single(VALUE str)
8622{
8623 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8624 bool modified = false;
8625
8626 while (s < send) {
8627 unsigned int c = *(unsigned char*)s;
8628
8629 if ('A' <= c && c <= 'Z') {
8630 *s = 'a' + (c - 'A');
8631 modified = true;
8632 }
8633 s++;
8634 }
8635
8636 return modified;
8637}
8638
8639/*
8640 * call-seq:
8641 * downcase!(mapping) -> self or nil
8642 *
8643 * Like String#downcase, except that:
8644 *
8645 * - Changes character casings in +self+ (not in a copy of +self+).
8646 * - Returns +self+ if any changes are made, +nil+ otherwise.
8647 *
8648 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8649 */
8650
8651static VALUE
8652rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
8653{
8654 rb_encoding *enc;
8655 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8656
8657 flags = check_case_options(argc, argv, flags);
8658 str_modify_keep_cr(str);
8659 enc = str_true_enc(str);
8660 if (case_option_single_p(flags, enc, str)) {
8661 if (downcase_single(str))
8662 flags |= ONIGENC_CASE_MODIFIED;
8663 }
8664 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8665 rb_str_ascii_casemap(str, str, &flags, enc);
8666 else
8667 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8668
8669 if (ONIGENC_CASE_MODIFIED&flags) return str;
8670 return Qnil;
8671}
8672
8673
8674/*
8675 * call-seq:
8676 * downcase(mapping = :ascii) -> new_string
8677 *
8678 * :include: doc/string/downcase.rdoc
8679 *
8680 */
8681
8682static VALUE
8683rb_str_downcase(int argc, VALUE *argv, VALUE str)
8684{
8685 rb_encoding *enc;
8686 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8687 VALUE ret;
8688
8689 flags = check_case_options(argc, argv, flags);
8690 enc = str_true_enc(str);
8691 if (case_option_single_p(flags, enc, str)) {
8692 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8693 str_enc_copy_direct(ret, str);
8694 downcase_single(ret);
8695 }
8696 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8697 ret = rb_str_new(0, RSTRING_LEN(str));
8698 rb_str_ascii_casemap(str, ret, &flags, enc);
8699 }
8700 else {
8701 ret = rb_str_casemap(str, &flags, enc);
8702 }
8703
8704 return ret;
8705}
8706
8707static bool
8708capitalize_single(VALUE str)
8709{
8710 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8711 bool modified = false;
8712
8713 if (s < send) {
8714 unsigned int c = (unsigned char)*s;
8715
8716 if ('a' <= c && c <= 'z') {
8717 *s = 'A' + (c - 'a');
8718 modified = true;
8719 }
8720 s++;
8721 }
8722 while (s < send) {
8723 unsigned int c = (unsigned char)*s;
8724
8725 if ('A' <= c && c <= 'Z') {
8726 *s = 'a' + (c - 'A');
8727 modified = true;
8728 }
8729 s++;
8730 }
8731
8732 return modified;
8733}
8734
8735/*
8736 * call-seq:
8737 * capitalize!(mapping = :ascii) -> self or nil
8738 *
8739 * Like String#capitalize, except that:
8740 *
8741 * - Changes character casings in +self+ (not in a copy of +self+).
8742 * - Returns +self+ if any changes are made, +nil+ otherwise.
8743 *
8744 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8745 */
8746
8747static VALUE
8748rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
8749{
8750 rb_encoding *enc;
8751 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
8752
8753 flags = check_case_options(argc, argv, flags);
8754 str_modify_keep_cr(str);
8755 enc = str_true_enc(str);
8756 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
8757 if (case_option_single_p(flags, enc, str)) {
8758 if (capitalize_single(str))
8759 flags |= ONIGENC_CASE_MODIFIED;
8760 }
8761 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8762 rb_str_ascii_casemap(str, str, &flags, enc);
8763 else
8764 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8765
8766 if (ONIGENC_CASE_MODIFIED&flags) return str;
8767 return Qnil;
8768}
8769
8770
8771/*
8772 * call-seq:
8773 * capitalize(mapping = :ascii) -> new_string
8774 *
8775 * :include: doc/string/capitalize.rdoc
8776 *
8777 */
8778
8779static VALUE
8780rb_str_capitalize(int argc, VALUE *argv, VALUE str)
8781{
8782 rb_encoding *enc;
8783 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
8784 VALUE ret;
8785
8786 flags = check_case_options(argc, argv, flags);
8787 enc = str_true_enc(str);
8788 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str;
8789 if (case_option_single_p(flags, enc, str)) {
8790 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8791 str_enc_copy_direct(ret, str);
8792 capitalize_single(ret);
8793 }
8794 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8795 ret = rb_str_new(0, RSTRING_LEN(str));
8796 rb_str_ascii_casemap(str, ret, &flags, enc);
8797 }
8798 else {
8799 ret = rb_str_casemap(str, &flags, enc);
8800 }
8801 return ret;
8802}
8803
8804
8805/*
8806 * call-seq:
8807 * swapcase!(mapping) -> self or nil
8808 *
8809 * Like String#swapcase, except that:
8810 *
8811 * - Changes are made to +self+, not to copy of +self+.
8812 * - Returns +self+ if any changes are made, +nil+ otherwise.
8813 *
8814 * Related: see {Modifying}[rdoc-ref:String@Modifying].
8815 */
8816
8817static VALUE
8818rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
8819{
8820 rb_encoding *enc;
8821 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
8822
8823 flags = check_case_options(argc, argv, flags);
8824 str_modify_keep_cr(str);
8825 enc = str_true_enc(str);
8826 if (flags&ONIGENC_CASE_ASCII_ONLY)
8827 rb_str_ascii_casemap(str, str, &flags, enc);
8828 else
8829 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8830
8831 if (ONIGENC_CASE_MODIFIED&flags) return str;
8832 return Qnil;
8833}
8834
8835
8836/*
8837 * call-seq:
8838 * swapcase(mapping = :ascii) -> new_string
8839 *
8840 * :include: doc/string/swapcase.rdoc
8841 *
8842 */
8843
8844static VALUE
8845rb_str_swapcase(int argc, VALUE *argv, VALUE str)
8846{
8847 rb_encoding *enc;
8848 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
8849 VALUE ret;
8850
8851 flags = check_case_options(argc, argv, flags);
8852 enc = str_true_enc(str);
8853 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str_duplicate(rb_cString, str);
8854 if (flags&ONIGENC_CASE_ASCII_ONLY) {
8855 ret = rb_str_new(0, RSTRING_LEN(str));
8856 rb_str_ascii_casemap(str, ret, &flags, enc);
8857 }
8858 else {
8859 ret = rb_str_casemap(str, &flags, enc);
8860 }
8861 return ret;
8862}
8863
8864typedef unsigned char *USTR;
8865
8866struct tr {
8867 int gen;
8868 unsigned int now, max;
8869 const char *p, *pend;
8870};
8871
8872static unsigned int
8873trnext(struct tr *t, rb_encoding *enc)
8874{
8875 int n;
8876
8877 for (;;) {
8878 nextpart:
8879 if (!t->gen) {
8880 if (t->p == t->pend) return -1;
8881 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '\\' && t->p + n < t->pend) {
8882 t->p += n;
8883 }
8884 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
8885 t->p += n;
8886 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '-' && t->p + n < t->pend) {
8887 t->p += n;
8888 if (t->p < t->pend) {
8889 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
8890 t->p += n;
8891 if (t->now > c) {
8892 if (t->now < 0x80 && c < 0x80) {
8893 rb_raise(rb_eArgError,
8894 "invalid range \"%c-%c\" in string transliteration",
8895 t->now, c);
8896 }
8897 else {
8898 rb_raise(rb_eArgError, "invalid range in string transliteration");
8899 }
8900 continue; /* not reached */
8901 }
8902 else if (t->now < c) {
8903 t->gen = 1;
8904 t->max = c;
8905 }
8906 }
8907 }
8908 return t->now;
8909 }
8910 else {
8911 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
8912 if (t->now == t->max) {
8913 t->gen = 0;
8914 goto nextpart;
8915 }
8916 }
8917 if (t->now < t->max) {
8918 return t->now;
8919 }
8920 else {
8921 t->gen = 0;
8922 return t->max;
8923 }
8924 }
8925 }
8926}
8927
8928static VALUE rb_str_delete_bang(int,VALUE*,VALUE);
8929
8930static VALUE
8931tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
8932{
8933 const unsigned int errc = -1;
8934 unsigned int trans[256];
8935 rb_encoding *enc, *e1, *e2;
8936 struct tr trsrc, trrepl;
8937 int cflag = 0;
8938 unsigned int c, c0, last = 0;
8939 int modify = 0, i, l;
8940 unsigned char *s, *send;
8941 VALUE hash = 0;
8942 int singlebyte = single_byte_optimizable(str);
8943 int termlen;
8944 int cr;
8945
8946#define CHECK_IF_ASCII(c) \
8947 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
8948 (cr = ENC_CODERANGE_VALID) : 0)
8949
8950 StringValue(src);
8951 StringValue(repl);
8952 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
8953 if (RSTRING_LEN(repl) == 0) {
8954 return rb_str_delete_bang(1, &src, str);
8955 }
8956
8957 cr = ENC_CODERANGE(str);
8958 e1 = rb_enc_check(str, src);
8959 e2 = rb_enc_check(str, repl);
8960 if (e1 == e2) {
8961 enc = e1;
8962 }
8963 else {
8964 enc = rb_enc_check(src, repl);
8965 }
8966 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
8967 if (RSTRING_LEN(src) > 1 &&
8968 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) == '^' &&
8969 trsrc.p + l < trsrc.pend) {
8970 cflag = 1;
8971 trsrc.p += l;
8972 }
8973 trrepl.p = RSTRING_PTR(repl);
8974 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
8975 trsrc.gen = trrepl.gen = 0;
8976 trsrc.now = trrepl.now = 0;
8977 trsrc.max = trrepl.max = 0;
8978
8979 if (cflag) {
8980 for (i=0; i<256; i++) {
8981 trans[i] = 1;
8982 }
8983 while ((c = trnext(&trsrc, enc)) != errc) {
8984 if (c < 256) {
8985 trans[c] = errc;
8986 }
8987 else {
8988 if (!hash) hash = rb_hash_new();
8989 rb_hash_aset(hash, UINT2NUM(c), Qtrue);
8990 }
8991 }
8992 while ((c = trnext(&trrepl, enc)) != errc)
8993 /* retrieve last replacer */;
8994 last = trrepl.now;
8995 for (i=0; i<256; i++) {
8996 if (trans[i] != errc) {
8997 trans[i] = last;
8998 }
8999 }
9000 }
9001 else {
9002 unsigned int r;
9003
9004 for (i=0; i<256; i++) {
9005 trans[i] = errc;
9006 }
9007 while ((c = trnext(&trsrc, enc)) != errc) {
9008 r = trnext(&trrepl, enc);
9009 if (r == errc) r = trrepl.now;
9010 if (c < 256) {
9011 trans[c] = r;
9012 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9013 }
9014 else {
9015 if (!hash) hash = rb_hash_new();
9016 rb_hash_aset(hash, UINT2NUM(c), UINT2NUM(r));
9017 }
9018 }
9019 }
9020
9021 if (cr == ENC_CODERANGE_VALID && rb_enc_asciicompat(e1))
9022 cr = ENC_CODERANGE_7BIT;
9023 str_modify_keep_cr(str);
9024 s = (unsigned char *)RSTRING_PTR(str); send = (unsigned char *)RSTRING_END(str);
9025 termlen = rb_enc_mbminlen(enc);
9026 if (sflag) {
9027 int clen, tlen;
9028 long offset, max = RSTRING_LEN(str);
9029 unsigned int save = -1;
9030 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9031
9032 while (s < send) {
9033 int may_modify = 0;
9034
9035 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9036 if (!MBCLEN_CHARFOUND_P(r)) {
9037 SIZED_FREE_N(buf, max + termlen);
9038 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9039 }
9040 clen = MBCLEN_CHARFOUND_LEN(r);
9041 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9042
9043 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9044
9045 s += clen;
9046 if (c < 256) {
9047 c = trans[c];
9048 }
9049 else if (hash) {
9050 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9051 if (NIL_P(tmp)) {
9052 if (cflag) c = last;
9053 else c = errc;
9054 }
9055 else if (cflag) c = errc;
9056 else c = NUM2INT(tmp);
9057 }
9058 else {
9059 c = errc;
9060 }
9061 if (c != (unsigned int)-1) {
9062 if (save == c) {
9063 CHECK_IF_ASCII(c);
9064 continue;
9065 }
9066 save = c;
9067 tlen = rb_enc_codelen(c, enc);
9068 modify = 1;
9069 }
9070 else {
9071 save = -1;
9072 c = c0;
9073 if (enc != e1) may_modify = 1;
9074 }
9075 if ((offset = t - buf) + tlen > max) {
9076 size_t MAYBE_UNUSED(old) = max + termlen;
9077 max = offset + tlen + (send - s);
9078 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9079 t = buf + offset;
9080 }
9081 rb_enc_mbcput(c, t, enc);
9082 if (may_modify && memcmp(s, t, tlen) != 0) {
9083 modify = 1;
9084 }
9085 CHECK_IF_ASCII(c);
9086 t += tlen;
9087 }
9088 if (!STR_EMBED_P(str)) {
9089 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9090 }
9091 TERM_FILL((char *)t, termlen);
9092 RSTRING(str)->as.heap.ptr = (char *)buf;
9093 STR_SET_LEN(str, t - buf);
9094 STR_SET_NOEMBED(str);
9095 RSTRING(str)->as.heap.aux.capa = max;
9096 }
9097 else if (rb_enc_mbmaxlen(enc) == 1 || (singlebyte && !hash)) {
9098 while (s < send) {
9099 c = (unsigned char)*s;
9100 if (trans[c] != errc) {
9101 if (!cflag) {
9102 c = trans[c];
9103 *s = c;
9104 modify = 1;
9105 }
9106 else {
9107 *s = last;
9108 modify = 1;
9109 }
9110 }
9111 CHECK_IF_ASCII(c);
9112 s++;
9113 }
9114 }
9115 else {
9116 int clen, tlen;
9117 long offset, max = (long)((send - s) * 1.2);
9118 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9119
9120 while (s < send) {
9121 int may_modify = 0;
9122
9123 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9124 if (!MBCLEN_CHARFOUND_P(r)) {
9125 SIZED_FREE_N(buf, max + termlen);
9126 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9127 }
9128 clen = MBCLEN_CHARFOUND_LEN(r);
9129 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9130
9131 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9132
9133 if (c < 256) {
9134 c = trans[c];
9135 }
9136 else if (hash) {
9137 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9138 if (NIL_P(tmp)) {
9139 if (cflag) c = last;
9140 else c = errc;
9141 }
9142 else if (cflag) c = errc;
9143 else c = NUM2INT(tmp);
9144 }
9145 else {
9146 c = cflag ? last : errc;
9147 }
9148 if (c != errc) {
9149 tlen = rb_enc_codelen(c, enc);
9150 modify = 1;
9151 }
9152 else {
9153 c = c0;
9154 if (enc != e1) may_modify = 1;
9155 }
9156 if ((offset = t - buf) + tlen > max) {
9157 size_t MAYBE_UNUSED(old) = max + termlen;
9158 max = offset + tlen + (long)((send - s) * 1.2);
9159 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9160 t = buf + offset;
9161 }
9162
9163 rb_enc_mbcput(c, t, enc);
9164 if (may_modify && memcmp(s, t, tlen) != 0) {
9165 modify = 1;
9166 }
9167 CHECK_IF_ASCII(c);
9168 s += clen;
9169 t += tlen;
9170 }
9171 if (!STR_EMBED_P(str)) {
9172 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9173 }
9174 TERM_FILL((char *)t, termlen);
9175 RSTRING(str)->as.heap.ptr = (char *)buf;
9176 STR_SET_LEN(str, t - buf);
9177 STR_SET_NOEMBED(str);
9178 RSTRING(str)->as.heap.aux.capa = max;
9179 }
9180
9181 if (modify) {
9182 if (cr != ENC_CODERANGE_BROKEN)
9183 ENC_CODERANGE_SET(str, cr);
9184 rb_enc_associate(str, enc);
9185 return str;
9186 }
9187 return Qnil;
9188}
9189
9191 unsigned char *buf;
9192 unsigned char *ptr;
9193 size_t capa;
9194 size_t initial_capa;
9195};
9196
9197static inline void
9198tr_buffer_init(struct tr_buffer *buffer, size_t initial_capa)
9199{
9200 if (initial_capa < 32) {
9201 initial_capa = 32;
9202 }
9203 *buffer = (struct tr_buffer){ .initial_capa = initial_capa };
9204}
9205
9206static inline void
9207tr_buffer_ensure_capa(struct tr_buffer *buffer, size_t extra_capa)
9208{
9209 size_t offset = buffer->ptr - buffer->buf;
9210 size_t required_capa = offset + extra_capa;
9211 if (UNLIKELY(buffer->capa < required_capa)) {
9212 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9213 RUBY_ASSERT(new_capa >= 32); // Lower would cause infinite loop
9214 while (new_capa < required_capa) {
9215 new_capa = (size_t)(new_capa * 1.2);
9216 }
9217 SIZED_REALLOC_N(buffer->buf, unsigned char, new_capa, buffer->capa);
9218 buffer->ptr = buffer->buf + offset;
9219 buffer->capa = new_capa;
9220 }
9221}
9222
9223static inline void
9224tr_buffer_append(struct tr_buffer *buffer, const unsigned char *ptr, size_t len)
9225{
9226 if (len) {
9227 tr_buffer_ensure_capa(buffer, len);
9228 memcpy(buffer->ptr, ptr, len);
9229 buffer->ptr += len;
9230 }
9231}
9232
9233static inline void
9234tr_buffer_append_str(struct tr_buffer *buffer, VALUE str)
9235{
9236 tr_buffer_append(buffer, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9237}
9238
9239static inline void
9240tr_buffer_mbcput(struct tr_buffer *buffer, int codepoint, rb_encoding *enc)
9241{
9242 tr_buffer_ensure_capa(buffer, 4);
9243 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9244}
9245
9246static inline void
9247tr_buffer_free(struct tr_buffer *buffer)
9248{
9249 if (buffer->buf) {
9250 SIZED_FREE_N(buffer->buf, buffer->capa);
9251 }
9252}
9253
9254struct tr_pair {
9255 VALUE search;
9256 VALUE replace;
9257};
9258
9260 struct tr_pair *pairs;
9261 size_t index;
9262 rb_encoding *enc;
9263 int cr;
9264};
9265
9266static int
9267tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9268{
9269 struct tr_trans_pairs_coerce_args *args = (struct tr_trans_pairs_coerce_args *)_args;
9270 struct tr_pair *pair = &args->pairs[args->index];
9271 args->index++;
9272
9273 VALUE search = (VALUE)key;
9274 VALUE replace = (VALUE)value;
9275 StringValue(search);
9276 StringValue(replace);
9277
9278 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9279 rb_raise(rb_eArgError, "keys must be of size 1"); // TODO: better error message
9280 }
9281
9282 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9283 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9284
9285 pair->search = search;
9286 pair->replace = replace;
9287 return ST_CONTINUE;
9288}
9289
9290#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9291
9293 const unsigned char *s;
9294 const unsigned char *send;
9295
9296#ifdef HAVE_SIMD
9297 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9298 int needles_count;
9299#ifdef HAVE_SIMD_NEON
9300 uint64_t matches_bitmap;
9301#endif
9302#ifdef HAVE_SIMD_SSE2
9303 int matches_bitmap;
9304#endif
9305#endif
9306
9307 VALUE trans_table[256];
9308};
9309
9310static inline VALUE
9311tr_trans_pairs_search_basic(struct tr_trans_pairs_search *search)
9312{
9313 while (search->s < search->send) {
9314 VALUE repl = search->trans_table[*search->s];
9315 if (UNLIKELY(repl)) {
9316 return repl;
9317 }
9318
9319 search->s++;
9320 }
9321
9322 return 0;
9323}
9324
9325#ifdef HAVE_SIMD_SSE2
9326static inline bool
9327tr_trans_pairs_next_match_sse2(struct tr_trans_pairs_search *search)
9328{
9329 size_t next_match_offset = ntz_int32(search->matches_bitmap);
9330 search->matches_bitmap >>= (next_match_offset + 1);
9331 search->s += next_match_offset;
9332 if (search->s > search->send) {
9333 search->s = search->send;
9334 return false;
9335 }
9336 return true;
9337}
9338
9339static inline VALUE
9340tr_trans_pairs_search_sse2(struct tr_trans_pairs_search *search)
9341{
9342 RBIMPL_ASSERT_OR_ASSUME(search->needles_count > 0);
9343 RBIMPL_ASSERT_OR_ASSUME(search->needles_count < TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9344
9345 if (search->matches_bitmap) {
9346 return tr_trans_pairs_next_match_sse2(search);
9347 }
9348
9349 if ((size_t)(search->send - search->s) >= sizeof(__m128i)) {
9350 int i;
9351 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9352 for (i = 0; i < search->needles_count; i++) {
9353 masks[i] = _mm_set1_epi8(search->needles[i]);
9354 }
9355
9356 do {
9357 const __m128i bytes = _mm_loadu_si128((__m128i const *)search->s);
9358
9359 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9360 for (i = 0; i < search->needles_count; i++) {
9361 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9362 }
9363
9364 for (i = i; i < search->needles_count; i++) {
9365 matches[0] = _mm_or_si128(matches[0], matches[i]);
9366 }
9367
9368 const int bitmap = _mm_movemask_epi8(matches[0]);
9369
9370 if (bitmap) {
9371 search->matches_bitmap = bitmap;
9372 return tr_trans_pairs_next_match_sse2(search);
9373 }
9374 search->s += sizeof(__m128i);
9375 } while ((size_t)(search->send - search->s) >= sizeof(__m128i));
9376 }
9377 return tr_trans_pairs_search_basic(search);
9378}
9379
9380#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9381#endif
9382
9383#ifdef HAVE_SIMD_NEON
9384static inline bool
9385tr_trans_pairs_next_match_neon(struct tr_trans_pairs_search *search)
9386{
9387 size_t next_match_offset = ntz_int64(search->matches_bitmap) / 4;
9388 search->matches_bitmap >>= (next_match_offset + 1) * 4;
9389 search->s += next_match_offset;
9390 if (search->s > search->send) {
9391 search->s = search->send;
9392 return false;
9393 }
9394 return true;
9395}
9396
9397static inline VALUE
9398tr_trans_pairs_search_neon(struct tr_trans_pairs_search *search)
9399{
9400 if (search->needles_count) {
9401 RBIMPL_ASSERT_OR_ASSUME(search->needles_count > 0);
9402 RBIMPL_ASSERT_OR_ASSUME(search->needles_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9403
9404 if (search->matches_bitmap) {
9405 return tr_trans_pairs_next_match_neon(search);
9406 }
9407
9408 if ((size_t)(search->send - search->s) >= sizeof(uint8x16_t)) {
9409 int i;
9410 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9411 for (i = 0; i < search->needles_count; i++) {
9412 masks[i] = vdupq_n_u8(search->needles[i]);
9413 }
9414
9415 do {
9416 const uint8x16_t bytes = vld1q_u8(search->s);
9417
9418 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9419 for (i = 0; i < search->needles_count; i++) {
9420 matches[i] = vceqq_u8(bytes, masks[i]);
9421 }
9422
9423 for (i = i; i < search->needles_count; i++) {
9424 matches[0] = vorrq_u8(matches[0], matches[i]);
9425 }
9426
9427 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9428 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0) & 0x8888888888888888ull;
9429
9430 if (bitmap) {
9431 search->matches_bitmap = bitmap;
9432 return tr_trans_pairs_next_match_neon(search);
9433 }
9434 search->s += sizeof(uint8x16_t);
9435 } while ((size_t)(search->send - search->s) >= sizeof(uint8x16_t));
9436 }
9437 }
9438 return tr_trans_pairs_search_basic(search);
9439}
9440
9441#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9442#endif
9443
9444#ifndef tr_trans_pairs_search_impl
9445#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9446#endif
9447
9448static VALUE
9449tr_trans_pairs(VALUE str, VALUE pairs_val)
9450{
9451 Check_Type(pairs_val, T_HASH);
9452 size_t pairs_count = RHASH_SIZE(pairs_val);
9453 rb_str_modify(str);
9454
9455 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0) return Qnil;
9456
9457 VALUE pairs_handle;
9458 struct tr_pair *pairs = ALLOCV_N(struct tr_pair, pairs_handle, pairs_count);
9459
9460 int cr = rb_enc_str_coderange(str);
9461 rb_encoding *enc = rb_str_enc_get(str);
9462
9463 struct tr_trans_pairs_coerce_args coerce_args = {
9464 .pairs = pairs,
9465 .enc = enc,
9466 .cr = cr,
9467 };
9468 rb_hash_foreach(pairs_val, tr_trans_pairs_coerce_i, (VALUE)&coerce_args);
9469 rb_encoding *e1 = coerce_args.enc;
9470
9471 VALUE hash = 0;
9472
9473 const unsigned char *sstart = (unsigned char *)RSTRING_PTR(str);
9474 long str_len = RSTRING_LEN(str);
9475 int termlen = rb_enc_mbminlen(e1);
9476
9477 struct tr_buffer buffer;
9478 tr_buffer_init(&buffer, str_len);
9479 bool modify = false;
9480
9481 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9482 struct tr_trans_pairs_search search = {
9483 .s = sstart,
9484 .send = sstart + str_len,
9485 };
9486
9487 for (size_t index = 0; index < pairs_count; index++) {
9488 struct tr_pair *pair = &pairs[index];
9489
9490 char *ptr = RSTRING_PTR(pair->search);
9491 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr, RSTRING_END(pair->search), e1);
9492
9493 const unsigned char first_byte = (unsigned char)*ptr;
9494
9495#ifdef HAVE_SIMD
9496 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9497 search.needles[index] = first_byte;
9498 search.needles_count++;
9499 }
9500#endif
9501
9502 if (rb_enc_codelen(codepoint, e1) == 1) {
9503 search.trans_table[first_byte] = pair->replace;
9504 }
9505 else {
9506 search.trans_table[first_byte] = Qundef;
9507 if (!hash) {
9508 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9509 }
9510 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9511 }
9512 }
9513
9514 const unsigned char *checkpoint = search.s;
9515 VALUE repl;
9516 while ((repl = tr_trans_pairs_search_impl(&search))) {
9517 int clen = 1;
9518
9519 if (UNLIKELY(repl == Qundef)) {
9520 unsigned int c = rb_enc_mbc_to_codepoint((char *)search.s, (char *)search.send, e1);
9521 clen = rb_enc_codelen(c, e1);
9522 repl = rb_hash_lookup2(hash, UINT2NUM(c), 0);
9523 if (!repl) {
9524 search.s += clen;
9525 continue;
9526 }
9527 }
9528
9529 modify = true;
9530
9531 if (checkpoint < search.s) {
9532 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9533 }
9534 tr_buffer_append_str(&buffer, repl);
9535 search.s += clen;
9536 checkpoint = search.s;
9537
9538 if (cr == ENC_CODERANGE_7BIT && rb_enc_str_coderange(repl) != ENC_CODERANGE_7BIT) {
9540 }
9541 }
9542
9543 if (modify && checkpoint < search.s) {
9544 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9545 }
9546 }
9547 else {
9548 const unsigned char *s = sstart;
9549 const unsigned char *send = sstart + str_len;
9550
9551 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9552
9553 for (size_t index = 0; index < pairs_count; index++) {
9554 struct tr_pair *pair = &pairs[index];
9555
9556 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search), RSTRING_END(pair->search), e1);
9557 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9558 }
9559
9560 while (s < send) {
9561 bool may_modify = false;
9562
9563 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9564 if (!MBCLEN_CHARFOUND_P(r)) {
9565 tr_buffer_free(&buffer);
9566 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9567 }
9568 int clen = MBCLEN_CHARFOUND_LEN(r);
9569 unsigned int c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9570 unsigned int c0 = c;
9571
9572 long tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
9573
9574 VALUE replacement = rb_hash_lookup(hash, UINT2NUM(c));
9575 if (NIL_P(replacement)) {
9576 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9577 c = c0;
9578 if (enc != e1) may_modify = true;
9579 }
9580 else {
9581 tlen = RSTRING_LEN(replacement);
9582 modify = true;
9583 }
9584
9585 if (NIL_P(replacement)) {
9586 tr_buffer_mbcput(&buffer, c, enc);
9587 }
9588 else {
9589 tr_buffer_append_str(&buffer, replacement);
9590 }
9591
9592 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
9593 modify = true;
9594 }
9595
9596 if (cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) {
9598 }
9599
9600 s += clen;
9601 }
9602 }
9603
9604 if (!STR_EMBED_P(str)) {
9605 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9606 }
9607 tr_buffer_ensure_capa(&buffer, termlen);
9608 TERM_FILL((char *)buffer.ptr, termlen);
9609 RSTRING(str)->as.heap.ptr = (char *)buffer.buf;
9610 STR_SET_LEN(str, buffer.ptr - buffer.buf);
9611 STR_SET_NOEMBED(str);
9612 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
9613
9614 RB_GC_GUARD(hash);
9615
9616 if (modify) {
9617 if (cr != ENC_CODERANGE_BROKEN)
9618 ENC_CODERANGE_SET(str, cr);
9619 rb_enc_associate(str, e1);
9620 return str;
9621 }
9622 return Qnil;
9623}
9624
9625/*
9626 * call-seq:
9627 * tr!(selector, replacements) -> self or nil
9628 * tr!(pairs) -> self or nil
9629 *
9630 * Like String#tr, except:
9631 *
9632 * - Performs substitutions in +self+ (not in a copy of +self+).
9633 * - Returns +self+ if any modifications were made, +nil+ otherwise.
9634 *
9635 * Related: {Modifying}[rdoc-ref:String@Modifying].
9636 */
9637
9638static VALUE
9639rb_str_tr_bang(int argc, VALUE *argv, VALUE str)
9640{
9641 rb_check_arity(argc, 1, 2);
9642
9643 if (argc == 1) {
9644 VALUE pairs = argv[0];
9645 return tr_trans_pairs(str, pairs);
9646 }
9647
9648 VALUE src = argv[0], repl = argv[1];
9649 return tr_trans(str, src, repl, 0);
9650}
9651
9652
9653/*
9654 * call-seq:
9655 * tr(selector, replacements) -> new_string
9656 *
9657 * Returns a copy of +self+ with each character specified by string +selector+
9658 * translated to the corresponding character in string +replacements+.
9659 * The correspondence is _positional_:
9660 *
9661 * - Each occurrence of the first character specified by +selector+
9662 * is translated to the first character in +replacements+.
9663 * - Each occurrence of the second character specified by +selector+
9664 * is translated to the second character in +replacements+.
9665 * - And so on.
9666 *
9667 * Example:
9668 *
9669 * 'hello'.tr('el', 'ip') #=> "hippo"
9670 *
9671 * If +replacements+ is shorter than +selector+,
9672 * it is implicitly padded with its own last character:
9673 *
9674 * 'hello'.tr('aeiou', '-') # => "h-ll-"
9675 * 'hello'.tr('aeiou', 'AA-') # => "hAll-"
9676 *
9677 * Arguments +selector+ and +replacements+ must be valid character selectors
9678 * (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
9679 * and may use any of its valid forms, including negation, ranges, and escapes:
9680 *
9681 * 'hello'.tr('^aeiou', '-') # => "-e--o" # Negation.
9682 * 'ibm'.tr('b-z', 'a-z') # => "hal" # Range.
9683 * 'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret.
9684 * 'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen.
9685 * 'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash.
9686 *
9687 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
9688 */
9689
9690static VALUE
9691rb_str_tr(int argc, VALUE *argv, VALUE str)
9692{
9693 rb_check_arity(argc, 1, 2);
9694
9695 str = str_duplicate(rb_cString, str);
9696
9697 if (argc == 1) {
9698 VALUE pairs = argv[0];
9699 return tr_trans_pairs(str, pairs);
9700 }
9701
9702 VALUE src = argv[0], repl = argv[1];
9703 tr_trans(str, src, repl, 0);
9704 return str;
9705}
9706
9707#define TR_TABLE_MAX (UCHAR_MAX+1)
9708#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
9709static void
9710tr_setup_table(VALUE str, char stable[TR_TABLE_SIZE], int first,
9711 VALUE *tablep, VALUE *ctablep, rb_encoding *enc)
9712{
9713 const unsigned int errc = -1;
9714 char buf[TR_TABLE_MAX];
9715 struct tr tr;
9716 unsigned int c;
9717 VALUE table = 0, ptable = 0;
9718 int i, l, cflag = 0;
9719
9720 tr.p = RSTRING_PTR(str); tr.pend = tr.p + RSTRING_LEN(str);
9721 tr.gen = tr.now = tr.max = 0;
9722
9723 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(tr.p, tr.pend, &l, enc) == '^') {
9724 cflag = 1;
9725 tr.p += l;
9726 }
9727 if (first) {
9728 for (i=0; i<TR_TABLE_MAX; i++) {
9729 stable[i] = 1;
9730 }
9731 stable[TR_TABLE_MAX] = cflag;
9732 }
9733 else if (stable[TR_TABLE_MAX] && !cflag) {
9734 stable[TR_TABLE_MAX] = 0;
9735 }
9736 for (i=0; i<TR_TABLE_MAX; i++) {
9737 buf[i] = cflag;
9738 }
9739
9740 while ((c = trnext(&tr, enc)) != errc) {
9741 if (c < TR_TABLE_MAX) {
9742 buf[(unsigned char)c] = !cflag;
9743 }
9744 else {
9745 VALUE key = UINT2NUM(c);
9746
9747 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
9748 if (cflag) {
9749 ptable = *ctablep;
9750 table = ptable ? ptable : rb_hash_new();
9751 *ctablep = table;
9752 }
9753 else {
9754 table = rb_hash_new();
9755 ptable = *tablep;
9756 *tablep = table;
9757 }
9758 }
9759 if (table && (!ptable || (cflag ^ !NIL_P(rb_hash_aref(ptable, key))))) {
9760 rb_hash_aset(table, key, Qtrue);
9761 }
9762 }
9763 }
9764 for (i=0; i<TR_TABLE_MAX; i++) {
9765 stable[i] = stable[i] && buf[i];
9766 }
9767 if (!table && !cflag) {
9768 *tablep = 0;
9769 }
9770}
9771
9772
9773static int
9774tr_find(unsigned int c, const char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
9775{
9776 if (c < TR_TABLE_MAX) {
9777 return table[c] != 0;
9778 }
9779 else {
9780 VALUE v = UINT2NUM(c);
9781
9782 if (del) {
9783 if (!NIL_P(rb_hash_lookup(del, v)) &&
9784 (!nodel || NIL_P(rb_hash_lookup(nodel, v)))) {
9785 return TRUE;
9786 }
9787 }
9788 else if (nodel && !NIL_P(rb_hash_lookup(nodel, v))) {
9789 return FALSE;
9790 }
9791 return table[TR_TABLE_MAX] ? TRUE : FALSE;
9792 }
9793}
9794
9795/*
9796 * call-seq:
9797 * delete!(*selectors) -> self or nil
9798 *
9799 * Like String#delete, but modifies +self+ in place;
9800 * returns +self+ if any characters were deleted, +nil+ otherwise.
9801 *
9802 * Related: see {Modifying}[rdoc-ref:String@Modifying].
9803 */
9804
9805static VALUE
9806rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
9807{
9808 char squeez[TR_TABLE_SIZE];
9809 rb_encoding *enc = 0;
9810 char *s, *send, *t;
9811 VALUE del = 0, nodel = 0;
9812 int modify = 0;
9813 int i, ascompat, cr;
9814
9815 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
9817 for (i=0; i<argc; i++) {
9818 VALUE s = argv[i];
9819
9820 StringValue(s);
9821 enc = rb_enc_check(str, s);
9822 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
9823 }
9824
9825 str_modify_keep_cr(str);
9826 ascompat = rb_enc_asciicompat(enc);
9827 s = t = RSTRING_PTR(str);
9828 send = RSTRING_END(str);
9829 cr = ascompat ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
9830 while (s < send) {
9831 unsigned int c;
9832 int clen;
9833
9834 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
9835 if (squeez[c]) {
9836 modify = 1;
9837 }
9838 else {
9839 if (t != s) *t = c;
9840 t++;
9841 }
9842 s++;
9843 }
9844 else {
9845 c = rb_enc_codepoint_len(s, send, &clen, enc);
9846
9847 if (tr_find(c, squeez, del, nodel)) {
9848 modify = 1;
9849 }
9850 else {
9851 if (t != s) rb_enc_mbcput(c, t, enc);
9852 t += clen;
9854 }
9855 s += clen;
9856 }
9857 }
9858 TERM_FILL(t, TERM_LEN(str));
9859 STR_SET_LEN(str, t - RSTRING_PTR(str));
9860 ENC_CODERANGE_SET(str, cr);
9861
9862 if (modify) return str;
9863 return Qnil;
9864}
9865
9866
9867/*
9868 * call-seq:
9869 * delete(*selectors) -> new_string
9870 *
9871 * :include: doc/string/delete.rdoc
9872 *
9873 */
9874
9875static VALUE
9876rb_str_delete(int argc, VALUE *argv, VALUE str)
9877{
9878 str = str_duplicate(rb_cString, str);
9879 rb_str_delete_bang(argc, argv, str);
9880 return str;
9881}
9882
9883
9884/*
9885 * call-seq:
9886 * squeeze!(*selectors) -> self or nil
9887 *
9888 * Like String#squeeze, except that:
9889 *
9890 * - Characters are squeezed in +self+ (not in a copy of +self+).
9891 * - Returns +self+ if any changes are made, +nil+ otherwise.
9892 *
9893 * Related: See {Modifying}[rdoc-ref:String@Modifying].
9894 */
9895
9896static VALUE
9897rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
9898{
9899 char squeez[TR_TABLE_SIZE];
9900 rb_encoding *enc = 0;
9901 VALUE del = 0, nodel = 0;
9902 unsigned char *s, *send, *t;
9903 int i, modify = 0;
9904 int ascompat, singlebyte = single_byte_optimizable(str);
9905 unsigned int save;
9906
9907 if (argc == 0) {
9908 enc = STR_ENC_GET(str);
9909 }
9910 else {
9911 for (i=0; i<argc; i++) {
9912 VALUE s = argv[i];
9913
9914 StringValue(s);
9915 enc = rb_enc_check(str, s);
9916 if (singlebyte && !single_byte_optimizable(s))
9917 singlebyte = 0;
9918 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
9919 }
9920 }
9921
9922 str_modify_keep_cr(str);
9923 s = t = (unsigned char *)RSTRING_PTR(str);
9924 if (!s || RSTRING_LEN(str) == 0) return Qnil;
9925 send = (unsigned char *)RSTRING_END(str);
9926 save = -1;
9927 ascompat = rb_enc_asciicompat(enc);
9928
9929 if (singlebyte) {
9930 while (s < send) {
9931 unsigned int c = *s++;
9932 if (c != save || (argc > 0 && !squeez[c])) {
9933 *t++ = save = c;
9934 }
9935 }
9936 }
9937 else {
9938 while (s < send) {
9939 unsigned int c;
9940 int clen;
9941
9942 if (ascompat && (c = *s) < 0x80) {
9943 if (c != save || (argc > 0 && !squeez[c])) {
9944 *t++ = save = c;
9945 }
9946 s++;
9947 }
9948 else {
9949 c = rb_enc_codepoint_len((char *)s, (char *)send, &clen, enc);
9950
9951 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
9952 if (t != s) rb_enc_mbcput(c, t, enc);
9953 save = c;
9954 t += clen;
9955 }
9956 s += clen;
9957 }
9958 }
9959 }
9960
9961 TERM_FILL((char *)t, TERM_LEN(str));
9962 if ((char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
9963 STR_SET_LEN(str, (char *)t - RSTRING_PTR(str));
9964 modify = 1;
9965 }
9966
9967 if (modify) return str;
9968 return Qnil;
9969}
9970
9971
9972/*
9973 * call-seq:
9974 * squeeze(*selectors) -> new_string
9975 *
9976 * :include: doc/string/squeeze.rdoc
9977 *
9978 */
9979
9980static VALUE
9981rb_str_squeeze(int argc, VALUE *argv, VALUE str)
9982{
9983 str = str_duplicate(rb_cString, str);
9984 rb_str_squeeze_bang(argc, argv, str);
9985 return str;
9986}
9987
9988
9989/*
9990 * call-seq:
9991 * tr_s!(selector, replacements) -> self or nil
9992 *
9993 * Like String#tr_s, except:
9994 *
9995 * - Modifies +self+ in place (not a copy of +self+).
9996 * - Returns +self+ if any changes were made, +nil+ otherwise.
9997 *
9998 * Related: {Modifying}[rdoc-ref:String@Modifying].
9999 */
10000
10001static VALUE
10002rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
10003{
10004 return tr_trans(str, src, repl, 1);
10005}
10006
10007
10008/*
10009 * call-seq:
10010 * tr_s(selector, replacements) -> new_string
10011 *
10012 * Like String#tr, except:
10013 *
10014 * - Also squeezes the modified portions of the translated string;
10015 * see String#squeeze.
10016 * - Returns the translated and squeezed string.
10017 *
10018 * Examples:
10019 *
10020 * 'hello'.tr_s('l', 'r') #=> "hero"
10021 * 'hello'.tr_s('el', '-') #=> "h-o"
10022 * 'hello'.tr_s('el', 'hx') #=> "hhxo"
10023 *
10024 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10025 *
10026 */
10027
10028static VALUE
10029rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
10030{
10031 str = str_duplicate(rb_cString, str);
10032 tr_trans(str, src, repl, 1);
10033 return str;
10034}
10035
10036
10037/*
10038 * call-seq:
10039 * count(*selectors) -> integer
10040 *
10041 * :include: doc/string/count.rdoc
10042 */
10043
10044static VALUE
10045rb_str_count(int argc, VALUE *argv, VALUE str)
10046{
10047 char table[TR_TABLE_SIZE];
10048 rb_encoding *enc = 0;
10049 VALUE del = 0, nodel = 0, tstr;
10050 const char *s, *send;
10051 int i;
10052 int ascompat;
10053 size_t n = 0;
10054
10056
10057 tstr = argv[0];
10058 StringValue(tstr);
10059 enc = rb_enc_check(str, tstr);
10060 if (argc == 1) {
10061 const char *ptstr;
10062 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10063 (ptstr = RSTRING_PTR(tstr),
10064 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
10065 !is_broken_string(str)) {
10066 int clen;
10067 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10068
10069 s = RSTRING_PTR(str);
10070 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10071 send = RSTRING_END(str);
10072 while (s < send) {
10073 if (*(unsigned char*)s++ == c) n++;
10074 }
10075 return SIZET2NUM(n);
10076 }
10077 }
10078
10079 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10080 for (i=1; i<argc; i++) {
10081 tstr = argv[i];
10082 StringValue(tstr);
10083 enc = rb_enc_check(str, tstr);
10084 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10085 }
10086
10087 s = RSTRING_PTR(str);
10088 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10089 send = RSTRING_END(str);
10090 ascompat = rb_enc_asciicompat(enc);
10091 while (s < send) {
10092 unsigned int c;
10093
10094 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
10095 if (table[c]) {
10096 n++;
10097 }
10098 s++;
10099 }
10100 else {
10101 int clen;
10102 c = rb_enc_codepoint_len(s, send, &clen, enc);
10103 if (tr_find(c, table, del, nodel)) {
10104 n++;
10105 }
10106 s += clen;
10107 }
10108 }
10109
10110 return SIZET2NUM(n);
10111}
10112
10113static VALUE
10114rb_fs_check(VALUE val)
10115{
10116 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING) && !RB_TYPE_P(val, T_REGEXP)) {
10117 val = rb_check_string_type(val);
10118 if (NIL_P(val)) return 0;
10119 }
10120 return val;
10121}
10122
10123static const char isspacetable[256] = {
10124 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10126 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10140};
10141
10142#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10143
10144static long
10145split_string(VALUE result, VALUE str, long beg, long len, long empty_count)
10146{
10147 if (empty_count >= 0 && len == 0) {
10148 return empty_count + 1;
10149 }
10150 if (empty_count > 0) {
10151 /* make different substrings */
10152 if (result) {
10153 do {
10154 rb_ary_push(result, str_new_empty_String(str));
10155 } while (--empty_count > 0);
10156 }
10157 else {
10158 do {
10159 rb_yield(str_new_empty_String(str));
10160 } while (--empty_count > 0);
10161 }
10162 }
10163 str = rb_str_subseq(str, beg, len);
10164 if (result) {
10165 rb_ary_push(result, str);
10166 }
10167 else {
10168 rb_yield(str);
10169 }
10170 return empty_count;
10171}
10172
10173typedef enum {
10174 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10175} split_type_t;
10176
10177static split_type_t
10178literal_split_pattern(VALUE spat, split_type_t default_type)
10179{
10180 rb_encoding *enc = STR_ENC_GET(spat);
10181 const char *ptr;
10182 long len;
10183 RSTRING_GETMEM(spat, ptr, len);
10184 if (len == 0) {
10185 /* Special case - split into chars */
10186 return SPLIT_TYPE_CHARS;
10187 }
10188 else if (rb_enc_asciicompat(enc)) {
10189 if (len == 1 && ptr[0] == ' ') {
10190 return SPLIT_TYPE_AWK;
10191 }
10192 }
10193 else {
10194 int l;
10195 if (rb_enc_ascget(ptr, ptr + len, &l, enc) == ' ' && len == l) {
10196 return SPLIT_TYPE_AWK;
10197 }
10198 }
10199 return default_type;
10200}
10201
10202/*
10203 * call-seq:
10204 * split(field_sep = $;, limit = 0) -> array_of_substrings
10205 * split(field_sep = $;, limit = 0) {|substring| ... } -> self
10206 *
10207 * :include: doc/string/split.rdoc
10208 *
10209 */
10210
10211static VALUE
10212rb_str_split_m(int argc, VALUE *argv, VALUE str)
10213{
10214 rb_encoding *enc;
10215 VALUE spat;
10216 VALUE limit;
10217 split_type_t split_type;
10218 long beg, end, i = 0, empty_count = -1;
10219 int lim = 0;
10220 VALUE result, tmp;
10221
10222 result = rb_block_given_p() ? Qfalse : Qnil;
10223 if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
10224 lim = NUM2INT(limit);
10225 if (lim <= 0) limit = Qnil;
10226 else if (lim == 1) {
10227 if (RSTRING_LEN(str) == 0)
10228 return result ? rb_ary_new2(0) : str;
10229 tmp = str_duplicate(rb_cString, str);
10230 if (!result) {
10231 rb_yield(tmp);
10232 return str;
10233 }
10234 return rb_ary_new3(1, tmp);
10235 }
10236 i = 1;
10237 }
10238 if (NIL_P(limit) && !lim) empty_count = 0;
10239
10240 enc = STR_ENC_GET(str);
10241 split_type = SPLIT_TYPE_REGEXP;
10242 if (!NIL_P(spat)) {
10243 spat = get_pat_quoted(spat, 0);
10244 }
10245 else if (NIL_P(spat = rb_fs)) {
10246 split_type = SPLIT_TYPE_AWK;
10247 }
10248 else if (!(spat = rb_fs_check(spat))) {
10249 rb_raise(rb_eTypeError, "value of $; must be String or Regexp");
10250 }
10251 else {
10252 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$; is set to non-nil value");
10253 }
10254 if (split_type != SPLIT_TYPE_AWK) {
10255 switch (BUILTIN_TYPE(spat)) {
10256 case T_REGEXP:
10257 rb_reg_options(spat); /* check if uninitialized */
10258 tmp = RREGEXP_SRC(spat);
10259 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10260 if (split_type == SPLIT_TYPE_AWK) {
10261 spat = tmp;
10262 split_type = SPLIT_TYPE_STRING;
10263 }
10264 break;
10265
10266 case T_STRING:
10267 mustnot_broken(spat);
10268 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10269 break;
10270
10271 default:
10273 }
10274 }
10275
10276#define SPLIT_STR(beg, len) ( \
10277 empty_count = split_string(result, str, beg, len, empty_count), \
10278 str_mod_check(str, str_start, str_len))
10279
10280 beg = 0;
10281 const char *ptr = RSTRING_PTR(str);
10282 const char *const str_start = ptr;
10283 const long str_len = RSTRING_LEN(str);
10284 const char *const eptr = str_start + str_len;
10285 if (split_type == SPLIT_TYPE_AWK) {
10286 const char *bptr = ptr;
10287 int skip = 1;
10288 unsigned int c;
10289
10290 if (result) result = rb_ary_new();
10291 end = beg;
10292 if (is_ascii_string(str)) {
10293 while (ptr < eptr) {
10294 c = (unsigned char)*ptr++;
10295 if (skip) {
10296 if (ascii_isspace(c)) {
10297 beg = ptr - bptr;
10298 }
10299 else {
10300 end = ptr - bptr;
10301 skip = 0;
10302 if (!NIL_P(limit) && lim <= i) break;
10303 }
10304 }
10305 else if (ascii_isspace(c)) {
10306 SPLIT_STR(beg, end-beg);
10307 skip = 1;
10308 beg = ptr - bptr;
10309 if (!NIL_P(limit)) ++i;
10310 }
10311 else {
10312 end = ptr - bptr;
10313 }
10314 }
10315 }
10316 else {
10317 while (ptr < eptr) {
10318 int n;
10319
10320 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10321 ptr += n;
10322 if (skip) {
10323 if (rb_isspace(c)) {
10324 beg = ptr - bptr;
10325 }
10326 else {
10327 end = ptr - bptr;
10328 skip = 0;
10329 if (!NIL_P(limit) && lim <= i) break;
10330 }
10331 }
10332 else if (rb_isspace(c)) {
10333 SPLIT_STR(beg, end-beg);
10334 skip = 1;
10335 beg = ptr - bptr;
10336 if (!NIL_P(limit)) ++i;
10337 }
10338 else {
10339 end = ptr - bptr;
10340 }
10341 }
10342 }
10343 }
10344 else if (split_type == SPLIT_TYPE_STRING) {
10345 const char *substr_start = ptr;
10346 const char *sptr = RSTRING_PTR(spat);
10347 long slen = RSTRING_LEN(spat);
10348
10349 if (result) result = rb_ary_new();
10350 mustnot_broken(str);
10351 enc = rb_enc_check(str, spat);
10352 while (ptr < eptr &&
10353 (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10354 /* Check we are at the start of a char */
10355 const char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc);
10356 if (t != ptr + end) {
10357 ptr = t;
10358 continue;
10359 }
10360 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10361 str_mod_check(spat, sptr, slen);
10362 ptr += end + slen;
10363 substr_start = ptr;
10364 if (!NIL_P(limit) && lim <= ++i) break;
10365 }
10366 beg = ptr - str_start;
10367 }
10368 else if (split_type == SPLIT_TYPE_CHARS) {
10369 int n;
10370
10371 if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
10372 mustnot_broken(str);
10373 enc = rb_enc_get(str);
10374 while (ptr < eptr &&
10375 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10376 SPLIT_STR(ptr - str_start, n);
10377 ptr += n;
10378 if (!NIL_P(limit) && lim <= ++i) break;
10379 }
10380 beg = ptr - str_start;
10381 }
10382 else {
10383 if (result) result = rb_ary_new();
10384 long len = RSTRING_LEN(str);
10385 long start = beg;
10386 int idx;
10387 int last_null = 0;
10388 VALUE match = 0;
10389
10390 for (; rb_reg_search(spat, str, start, 0) >= 0;
10391 (match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
10392 match = rb_backref_get();
10393 if (!result) rb_match_busy(match);
10394 end = RMATCH_BEG(match, 0);
10395 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10396 if (!ptr) {
10397 SPLIT_STR(0, 0);
10398 break;
10399 }
10400 else if (last_null == 1) {
10401 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10402 beg = start;
10403 }
10404 else {
10405 if (start == len)
10406 start++;
10407 else
10408 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10409 last_null = 1;
10410 continue;
10411 }
10412 }
10413 else {
10414 SPLIT_STR(beg, end-beg);
10415 beg = start = RMATCH_END(match, 0);
10416 }
10417 last_null = 0;
10418
10419 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10420 if (RMATCH_BEG(match, idx) == -1) continue;
10421 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10422 }
10423 if (!NIL_P(limit) && lim <= ++i) break;
10424 }
10425 if (match) rb_match_unbusy(match);
10426 }
10427 if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10428 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10429 }
10430
10431 return result ? result : str;
10432}
10433
10434VALUE
10435rb_str_split(VALUE str, const char *sep0)
10436{
10437 VALUE sep;
10438
10439 StringValue(str);
10440 sep = rb_str_new_cstr(sep0);
10441 return rb_str_split_m(1, &sep, str);
10442}
10443
10444#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10445
10446static inline int
10447enumerator_element(VALUE ary, VALUE e)
10448{
10449 if (ary) {
10450 rb_ary_push(ary, e);
10451 return 0;
10452 }
10453 else {
10454 rb_yield(e);
10455 return 1;
10456 }
10457}
10458
10459#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10460
10461static const char *
10462chomp_newline(const char *p, const char *e, rb_encoding *enc)
10463{
10464 const char *prev = rb_enc_prev_char(p, e, e, enc);
10465 if (rb_enc_is_newline(prev, e, enc)) {
10466 e = prev;
10467 prev = rb_enc_prev_char(p, e, e, enc);
10468 if (prev && rb_enc_ascget(prev, e, NULL, enc) == '\r')
10469 e = prev;
10470 }
10471 return e;
10472}
10473
10474static VALUE
10475get_rs(void)
10476{
10477 VALUE rs = rb_rs;
10478 if (!NIL_P(rs) &&
10479 (!RB_TYPE_P(rs, T_STRING) ||
10480 RSTRING_LEN(rs) != 1 ||
10481 RSTRING_PTR(rs)[0] != '\n')) {
10482 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$/ is set to non-default value");
10483 }
10484 return rs;
10485}
10486
10487#define rb_rs get_rs()
10488
10489static VALUE
10490rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
10491{
10492 rb_encoding *enc;
10493 VALUE line, rs, orig = str, opts = Qnil, chomp = Qfalse;
10494 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10495 long pos, rslen;
10496 int rsnewline = 0;
10497
10498 if (rb_scan_args(argc, argv, "01:", &rs, &opts) == 0)
10499 rs = rb_rs;
10500 if (!NIL_P(opts)) {
10501 static ID keywords[1];
10502 if (!keywords[0]) {
10503 keywords[0] = rb_intern_const("chomp");
10504 }
10505 rb_get_kwargs(opts, keywords, 0, 1, &chomp);
10506 chomp = (!UNDEF_P(chomp) && RTEST(chomp));
10507 }
10508
10509 if (NIL_P(rs)) {
10510 if (!ENUM_ELEM(ary, str)) {
10511 return ary;
10512 }
10513 else {
10514 return orig;
10515 }
10516 }
10517
10518 if (!RSTRING_LEN(str)) goto end;
10519 str = rb_str_new_frozen(str);
10520 const char *const ptr = subptr = RSTRING_PTR(str);
10521 const long len = RSTRING_LEN(str);
10522 pend = RSTRING_END(str);
10523 StringValue(rs);
10524 rslen = RSTRING_LEN(rs);
10525
10526 if (rs == rb_default_rs)
10527 enc = rb_enc_get(str);
10528 else
10529 enc = rb_enc_check(str, rs);
10530
10531 if (rslen == 0) {
10532 /* paragraph mode */
10533 int n;
10534 const char *eol = NULL;
10535 subend = subptr;
10536 while (subend < pend) {
10537 long chomp_rslen = 0;
10538 do {
10539 if (rb_enc_ascget(subend, pend, &n, enc) != '\r')
10540 n = 0;
10541 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
10542 if (rb_enc_is_newline(subend + n, pend, enc)) {
10543 if (eol == subend) break;
10544 subend += rslen;
10545 if (subptr) {
10546 eol = subend;
10547 chomp_rslen = -rslen;
10548 }
10549 }
10550 else {
10551 if (!subptr) subptr = subend;
10552 subend += rslen;
10553 }
10554 rslen = 0;
10555 } while (subend < pend);
10556 if (!subptr) break;
10557 if (rslen == 0) chomp_rslen = 0;
10558 line = rb_str_subseq(str, subptr - ptr,
10559 subend - subptr + (chomp ? chomp_rslen : rslen));
10560 if (ENUM_ELEM(ary, line)) {
10561 str_mod_check(str, ptr, len);
10562 }
10563 subptr = eol = NULL;
10564 }
10565 goto end;
10566 }
10567 else {
10568 rsptr = RSTRING_PTR(rs);
10569 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
10570 rb_enc_is_newline(rsptr, rsptr + RSTRING_LEN(rs), enc)) {
10571 rsnewline = 1;
10572 }
10573 }
10574
10575 if ((rs == rb_default_rs) && !rb_enc_asciicompat(enc)) {
10576 rs = rb_str_new(rsptr, rslen);
10577 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
10578 rsptr = RSTRING_PTR(rs);
10579 rslen = RSTRING_LEN(rs);
10580 }
10581
10582 while (subptr < pend) {
10583 pos = rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
10584 if (pos < 0) break;
10585 hit = subptr + pos;
10586 adjusted = rb_enc_right_char_head(subptr, hit, pend, enc);
10587 if (hit != adjusted) {
10588 subptr = adjusted;
10589 continue;
10590 }
10591 subend = hit += rslen;
10592 if (chomp) {
10593 if (rsnewline) {
10594 subend = chomp_newline(subptr, subend, enc);
10595 }
10596 else {
10597 subend -= rslen;
10598 }
10599 }
10600 line = rb_str_subseq(str, subptr - ptr, subend - subptr);
10601 if (ENUM_ELEM(ary, line)) {
10602 str_mod_check(str, ptr, len);
10603 }
10604 subptr = hit;
10605 }
10606
10607 if (subptr != pend) {
10608 if (chomp) {
10609 if (rsnewline) {
10610 pend = chomp_newline(subptr, pend, enc);
10611 }
10612 else if (pend - subptr >= rslen &&
10613 memcmp(pend - rslen, rsptr, rslen) == 0) {
10614 pend -= rslen;
10615 }
10616 }
10617 line = rb_str_subseq(str, subptr - ptr, pend - subptr);
10618 ENUM_ELEM(ary, line);
10619 RB_GC_GUARD(str);
10620 }
10621
10622 end:
10623 if (ary)
10624 return ary;
10625 else
10626 return orig;
10627}
10628
10629/*
10630 * call-seq:
10631 * each_line(record_separator = $/, chomp: false) {|substring| ... } -> self
10632 * each_line(record_separator = $/, chomp: false) -> enumerator
10633 *
10634 * :include: doc/string/each_line.rdoc
10635 *
10636 */
10637
10638static VALUE
10639rb_str_each_line(int argc, VALUE *argv, VALUE str)
10640{
10641 RETURN_SIZED_ENUMERATOR(str, argc, argv, 0);
10642 return rb_str_enumerate_lines(argc, argv, str, 0);
10643}
10644
10645/*
10646 * call-seq:
10647 * lines(record_separator = $/, chomp: false) -> array_of_strings
10648 *
10649 * Returns substrings ("lines") of +self+
10650 * according to the given arguments:
10651 *
10652 * s = <<~EOT
10653 * This is the first line.
10654 * This is line two.
10655 *
10656 * This is line four.
10657 * This is line five.
10658 * EOT
10659 *
10660 * With the default argument values:
10661 *
10662 * $/ # => "\n"
10663 * s.lines
10664 * # =>
10665 * ["This is the first line.\n",
10666 * "This is line two.\n",
10667 * "\n",
10668 * "This is line four.\n",
10669 * "This is line five.\n"]
10670 *
10671 * With a different +record_separator+:
10672 *
10673 * record_separator = ' is '
10674 * s.lines(record_separator)
10675 * # =>
10676 * ["This is ",
10677 * "the first line.\nThis is ",
10678 * "line two.\n\nThis is ",
10679 * "line four.\nThis is ",
10680 * "line five.\n"]
10681 *
10682 * With keyword argument +chomp+ as +true+,
10683 * removes the trailing newline from each line:
10684 *
10685 * s.lines(chomp: true)
10686 * # =>
10687 * ["This is the first line.",
10688 * "This is line two.",
10689 * "",
10690 * "This is line four.",
10691 * "This is line five."]
10692 *
10693 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
10694 */
10695
10696static VALUE
10697rb_str_lines(int argc, VALUE *argv, VALUE str)
10698{
10699 VALUE ary = WANTARRAY("lines", 0);
10700 return rb_str_enumerate_lines(argc, argv, str, ary);
10701}
10702
10703static VALUE
10704rb_str_each_byte_size(VALUE str, VALUE args, VALUE eobj)
10705{
10706 return LONG2FIX(RSTRING_LEN(str));
10707}
10708
10709static VALUE
10710rb_str_enumerate_bytes(VALUE str, VALUE ary)
10711{
10712 long i;
10713
10714 for (i=0; i<RSTRING_LEN(str); i++) {
10715 ENUM_ELEM(ary, INT2FIX((unsigned char)RSTRING_PTR(str)[i]));
10716 }
10717 if (ary)
10718 return ary;
10719 else
10720 return str;
10721}
10722
10723/*
10724 * call-seq:
10725 * each_byte {|byte| ... } -> self
10726 * each_byte -> enumerator
10727 *
10728 * :include: doc/string/each_byte.rdoc
10729 *
10730 */
10731
10732static VALUE
10733rb_str_each_byte(VALUE str)
10734{
10735 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_byte_size);
10736 return rb_str_enumerate_bytes(str, 0);
10737}
10738
10739/*
10740 * call-seq:
10741 * bytes -> array_of_bytes
10742 *
10743 * :include: doc/string/bytes.rdoc
10744 *
10745 */
10746
10747static VALUE
10748rb_str_bytes(VALUE str)
10749{
10750 VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
10751 return rb_str_enumerate_bytes(str, ary);
10752}
10753
10754static VALUE
10755rb_str_each_char_size(VALUE str, VALUE args, VALUE eobj)
10756{
10757 return rb_str_length(str);
10758}
10759
10760static VALUE
10761rb_str_enumerate_chars(VALUE str, VALUE ary)
10762{
10763 VALUE orig = str;
10764 long i, len, n;
10765 const char *ptr;
10766 rb_encoding *enc;
10767
10768 str = rb_str_new_frozen(str);
10769 ptr = RSTRING_PTR(str);
10770 len = RSTRING_LEN(str);
10771 enc = rb_enc_get(str);
10772
10774 for (i = 0; i < len; i += n) {
10775 n = rb_enc_fast_mbclen(ptr + i, ptr + len, enc);
10776 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
10777 }
10778 }
10779 else {
10780 for (i = 0; i < len; i += n) {
10781 n = rb_enc_mbclen(ptr + i, ptr + len, enc);
10782 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
10783 }
10784 }
10785 RB_GC_GUARD(str);
10786 if (ary)
10787 return ary;
10788 else
10789 return orig;
10790}
10791
10792/*
10793 * call-seq:
10794 * each_char {|char| ... } -> self
10795 * each_char -> enumerator
10796 *
10797 * :include: doc/string/each_char.rdoc
10798 *
10799 */
10800
10801static VALUE
10802rb_str_each_char(VALUE str)
10803{
10804 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
10805 return rb_str_enumerate_chars(str, 0);
10806}
10807
10808/*
10809 * call-seq:
10810 * chars -> array_of_characters
10811 *
10812 * :include: doc/string/chars.rdoc
10813 *
10814 */
10815
10816static VALUE
10817rb_str_chars(VALUE str)
10818{
10819 VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
10820 return rb_str_enumerate_chars(str, ary);
10821}
10822
10823static VALUE
10824rb_str_enumerate_codepoints(VALUE str, VALUE ary)
10825{
10826 VALUE orig = str;
10827 int n;
10828 unsigned int c;
10829 const char *ptr, *end;
10830 rb_encoding *enc;
10831 int enc_asciicompat;
10832
10833 if (single_byte_optimizable(str))
10834 return rb_str_enumerate_bytes(str, ary);
10835
10836 str = rb_str_new_frozen(str);
10837 ptr = RSTRING_PTR(str);
10838 end = RSTRING_END(str);
10839 enc = STR_ENC_GET(str);
10840 enc_asciicompat = rb_enc_asciicompat(enc);
10841
10842 while (ptr < end) {
10843 /* Fast path: ASCII byte in an ASCII-compatible encoding is its own codepoint;
10844 * skip rb_enc_codepoint_len and return the byte directly.
10845 */
10846 n = 1;
10847 c = (enc_asciicompat && ISASCII(*ptr)) ?
10848 (unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
10849 ENUM_ELEM(ary, UINT2NUM(c));
10850 ptr += n;
10851 }
10852 RB_GC_GUARD(str);
10853 if (ary)
10854 return ary;
10855 else
10856 return orig;
10857}
10858
10859/*
10860 * call-seq:
10861 * each_codepoint {|codepoint| ... } -> self
10862 * each_codepoint -> enumerator
10863 *
10864 * :include: doc/string/each_codepoint.rdoc
10865 *
10866 */
10867
10868static VALUE
10869rb_str_each_codepoint(VALUE str)
10870{
10871 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
10872 return rb_str_enumerate_codepoints(str, 0);
10873}
10874
10875/*
10876 * call-seq:
10877 * codepoints -> array_of_integers
10878 *
10879 * :include: doc/string/codepoints.rdoc
10880 *
10881 */
10882
10883static VALUE
10884rb_str_codepoints(VALUE str)
10885{
10886 VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
10887 return rb_str_enumerate_codepoints(str, ary);
10888}
10889
10890static regex_t *
10891get_reg_grapheme_cluster(rb_encoding *enc)
10892{
10893 int encidx = rb_enc_to_index(enc);
10894
10895 const OnigUChar source_ascii[] = "\\X";
10896 const OnigUChar *source = source_ascii;
10897 size_t source_len = sizeof(source_ascii) - 1;
10898
10899 switch (encidx) {
10900#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
10901#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
10902#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
10903#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
10904#define CASE_UTF(e) \
10905 case ENCINDEX_UTF_##e: { \
10906 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
10907 source = source_UTF_##e; \
10908 source_len = sizeof(source_UTF_##e); \
10909 break; \
10910 }
10911 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
10912#undef CASE_UTF
10913#undef CHARS_16BE
10914#undef CHARS_16LE
10915#undef CHARS_32BE
10916#undef CHARS_32LE
10917 }
10918
10919 regex_t *reg_grapheme_cluster;
10920 OnigErrorInfo einfo;
10921 int r = onig_new(&reg_grapheme_cluster, source, source + source_len,
10922 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
10923 if (r) {
10924 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
10925 onig_error_code_to_str(message, r, &einfo);
10926 rb_fatal("cannot compile grapheme cluster regexp: %s", (char *)message);
10927 }
10928
10929 return reg_grapheme_cluster;
10930}
10931
10932static regex_t *
10933get_cached_reg_grapheme_cluster(rb_encoding *enc)
10934{
10935 int encidx = rb_enc_to_index(enc);
10936 static regex_t *reg_grapheme_cluster_utf8 = NULL;
10937
10938 if (encidx == rb_utf8_encindex()) {
10939 if (!reg_grapheme_cluster_utf8) {
10940 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
10941 }
10942
10943 return reg_grapheme_cluster_utf8;
10944 }
10945
10946 return NULL;
10947}
10948
10949static VALUE
10950rb_str_each_grapheme_cluster_size(VALUE str, VALUE args, VALUE eobj)
10951{
10952 size_t grapheme_cluster_count = 0;
10953 rb_encoding *enc = get_encoding(str);
10954 const char *ptr, *end;
10955
10956 if (!rb_enc_unicode_p(enc)) {
10957 return rb_str_length(str);
10958 }
10959
10960 bool cached_reg_grapheme_cluster = true;
10961 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
10962 if (!reg_grapheme_cluster) {
10963 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
10964 cached_reg_grapheme_cluster = false;
10965 }
10966
10967 ptr = RSTRING_PTR(str);
10968 end = RSTRING_END(str);
10969
10970 while (ptr < end) {
10971 OnigPosition len = onig_match(reg_grapheme_cluster,
10972 (const OnigUChar *)ptr, (const OnigUChar *)end,
10973 (const OnigUChar *)ptr, NULL, 0);
10974 if (len <= 0) break;
10975 grapheme_cluster_count++;
10976 ptr += len;
10977 }
10978
10979 if (!cached_reg_grapheme_cluster) {
10980 onig_free(reg_grapheme_cluster);
10981 }
10982
10983 return SIZET2NUM(grapheme_cluster_count);
10984}
10985
10986static VALUE
10987rb_str_enumerate_grapheme_clusters(VALUE str, VALUE ary)
10988{
10989 VALUE orig = str;
10990 rb_encoding *enc = get_encoding(str);
10991 const char *ptr0, *ptr, *end;
10992
10993 if (!rb_enc_unicode_p(enc)) {
10994 return rb_str_enumerate_chars(str, ary);
10995 }
10996
10997 if (!ary) str = rb_str_new_frozen(str);
10998
10999 bool cached_reg_grapheme_cluster = true;
11000 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11001 if (!reg_grapheme_cluster) {
11002 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11003 cached_reg_grapheme_cluster = false;
11004 }
11005
11006 ptr0 = ptr = RSTRING_PTR(str);
11007 end = RSTRING_END(str);
11008
11009 while (ptr < end) {
11010 OnigPosition len = onig_match(reg_grapheme_cluster,
11011 (const OnigUChar *)ptr, (const OnigUChar *)end,
11012 (const OnigUChar *)ptr, NULL, 0);
11013 if (len <= 0) break;
11014 ENUM_ELEM(ary, rb_str_subseq(str, ptr-ptr0, len));
11015 ptr += len;
11016 }
11017
11018 if (!cached_reg_grapheme_cluster) {
11019 onig_free(reg_grapheme_cluster);
11020 }
11021
11022 RB_GC_GUARD(str);
11023 if (ary)
11024 return ary;
11025 else
11026 return orig;
11027}
11028
11029/*
11030 * call-seq:
11031 * each_grapheme_cluster {|grapheme_cluster| ... } -> self
11032 * each_grapheme_cluster -> enumerator
11033 *
11034 * :include: doc/string/each_grapheme_cluster.rdoc
11035 *
11036 */
11037
11038static VALUE
11039rb_str_each_grapheme_cluster(VALUE str)
11040{
11041 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_grapheme_cluster_size);
11042 return rb_str_enumerate_grapheme_clusters(str, 0);
11043}
11044
11045/*
11046 * call-seq:
11047 * grapheme_clusters -> array_of_grapheme_clusters
11048 *
11049 * :include: doc/string/grapheme_clusters.rdoc
11050 *
11051 */
11052
11053static VALUE
11054rb_str_grapheme_clusters(VALUE str)
11055{
11056 VALUE ary = WANTARRAY("grapheme_clusters", rb_str_strlen(str));
11057 return rb_str_enumerate_grapheme_clusters(str, ary);
11058}
11059
11060static long
11061chopped_length(VALUE str)
11062{
11063 rb_encoding *enc = STR_ENC_GET(str);
11064 const char *p, *p2, *beg, *end;
11065
11066 beg = RSTRING_PTR(str);
11067 end = beg + RSTRING_LEN(str);
11068 if (beg >= end) return 0;
11069 p = rb_enc_prev_char(beg, end, end, enc);
11070 if (!p) return 0;
11071 if (p > beg && rb_enc_ascget(p, end, 0, enc) == '\n') {
11072 p2 = rb_enc_prev_char(beg, p, end, enc);
11073 if (p2 && rb_enc_ascget(p2, end, 0, enc) == '\r') p = p2;
11074 }
11075 return p - beg;
11076}
11077
11078/*
11079 * call-seq:
11080 * chop! -> self or nil
11081 *
11082 * Like String#chop, except that:
11083 *
11084 * - Removes trailing characters from +self+ (not from a copy of +self+).
11085 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11086 *
11087 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11088 */
11089
11090static VALUE
11091rb_str_chop_bang(VALUE str)
11092{
11093 str_modify_keep_cr(str);
11094 if (RSTRING_LEN(str) > 0) {
11095 long len;
11096 len = chopped_length(str);
11097 STR_SET_LEN(str, len);
11098 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11099 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11101 }
11102 return str;
11103 }
11104 return Qnil;
11105}
11106
11107
11108/*
11109 * call-seq:
11110 * chop -> new_string
11111 *
11112 * :include: doc/string/chop.rdoc
11113 *
11114 */
11115
11116static VALUE
11117rb_str_chop(VALUE str)
11118{
11119 return rb_str_subseq(str, 0, chopped_length(str));
11120}
11121
11122static long
11123smart_chomp(VALUE str, const char *e, const char *p)
11124{
11125 rb_encoding *enc = rb_enc_get(str);
11126 if (rb_enc_mbminlen(enc) > 1) {
11127 const char *pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11128 if (rb_enc_is_newline(pp, e, enc)) {
11129 e = pp;
11130 }
11131 pp = e - rb_enc_mbminlen(enc);
11132 if (pp >= p) {
11133 pp = rb_enc_left_char_head(p, pp, e, enc);
11134 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11135 e = pp;
11136 }
11137 }
11138 }
11139 else {
11140 switch (*(e-1)) { /* not e[-1] to get rid of VC bug */
11141 case '\n':
11142 if (--e > p && *(e-1) == '\r') {
11143 --e;
11144 }
11145 break;
11146 case '\r':
11147 --e;
11148 break;
11149 }
11150 }
11151 return e - p;
11152}
11153
11154static long
11155chompped_length(VALUE str, VALUE rs)
11156{
11157 rb_encoding *enc;
11158 int newline;
11159 const char *pp, *e, *rsptr;
11160 long rslen;
11161 const char *const p = RSTRING_PTR(str);
11162 long len = RSTRING_LEN(str);
11163
11164 if (len == 0) return 0;
11165 e = p + len;
11166 if (rs == rb_default_rs) {
11167 return smart_chomp(str, e, p);
11168 }
11169
11170 enc = rb_enc_get(str);
11171 RSTRING_GETMEM(rs, rsptr, rslen);
11172 if (rslen == 0) {
11173 if (rb_enc_mbminlen(enc) > 1) {
11174 while (e > p) {
11175 pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11176 if (!rb_enc_is_newline(pp, e, enc)) break;
11177 e = pp;
11178 pp -= rb_enc_mbminlen(enc);
11179 if (pp >= p) {
11180 pp = rb_enc_left_char_head(p, pp, e, enc);
11181 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11182 e = pp;
11183 }
11184 }
11185 }
11186 }
11187 else {
11188 while (e > p && *(e-1) == '\n') {
11189 --e;
11190 if (e > p && *(e-1) == '\r')
11191 --e;
11192 }
11193 }
11194 return e - p;
11195 }
11196 if (rslen > len) return len;
11197
11198 enc = rb_enc_get(rs);
11199 newline = rsptr[rslen-1];
11200 if (rslen == rb_enc_mbminlen(enc)) {
11201 if (rslen == 1) {
11202 if (newline == '\n')
11203 return smart_chomp(str, e, p);
11204 }
11205 else {
11206 if (rb_enc_is_newline(rsptr, rsptr+rslen, enc))
11207 return smart_chomp(str, e, p);
11208 }
11209 }
11210
11211 enc = rb_enc_check(str, rs);
11212 if (is_broken_string(rs)) {
11213 return len;
11214 }
11215 pp = e - rslen;
11216 if (p[len-1] == newline &&
11217 (rslen <= 1 ||
11218 memcmp(rsptr, pp, rslen) == 0)) {
11219 if (at_char_boundary(p, pp, e, enc))
11220 return len - rslen;
11221 RB_GC_GUARD(rs);
11222 }
11223 return len;
11224}
11225
11231static VALUE
11232chomp_rs(int argc, const VALUE *argv)
11233{
11234 rb_check_arity(argc, 0, 1);
11235 if (argc > 0) {
11236 VALUE rs = argv[0];
11237 if (!NIL_P(rs)) StringValue(rs);
11238 return rs;
11239 }
11240 else {
11241 return rb_rs;
11242 }
11243}
11244
11245VALUE
11246rb_str_chomp_string(VALUE str, VALUE rs)
11247{
11248 long olen = RSTRING_LEN(str);
11249 long len = chompped_length(str, rs);
11250 if (len >= olen) return Qnil;
11251 str_modify_keep_cr(str);
11252 STR_SET_LEN(str, len);
11253 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11254 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11256 }
11257 return str;
11258}
11259
11260/*
11261 * call-seq:
11262 * chomp!(line_sep = $/) -> self or nil
11263 *
11264 * Like String#chomp, except that:
11265 *
11266 * - Removes trailing characters from +self+ (not from a copy of +self+).
11267 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11268 *
11269 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11270 */
11271
11272static VALUE
11273rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
11274{
11275 VALUE rs;
11276 str_modifiable(str);
11277 if (RSTRING_LEN(str) == 0 && argc < 2) return Qnil;
11278 rs = chomp_rs(argc, argv);
11279 if (NIL_P(rs)) return Qnil;
11280 return rb_str_chomp_string(str, rs);
11281}
11282
11283
11284/*
11285 * call-seq:
11286 * chomp(line_sep = $/) -> new_string
11287 *
11288 * :include: doc/string/chomp.rdoc
11289 *
11290 */
11291
11292static VALUE
11293rb_str_chomp(int argc, VALUE *argv, VALUE str)
11294{
11295 VALUE rs = chomp_rs(argc, argv);
11296 if (NIL_P(rs)) return str_duplicate(rb_cString, str);
11297 return rb_str_subseq(str, 0, chompped_length(str, rs));
11298}
11299
11300static void
11301tr_setup_table_multi(char table[TR_TABLE_SIZE], VALUE *tablep, VALUE *ctablep,
11302 VALUE str, int num_selectors, VALUE *selectors)
11303{
11304 int i;
11305
11306 for (i=0; i<num_selectors; i++) {
11307 VALUE selector = selectors[i];
11308 rb_encoding *enc;
11309
11310 StringValue(selector);
11311 enc = rb_enc_check(str, selector);
11312 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11313 }
11314}
11315
11316static long
11317lstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11318{
11319 const char *const start = s;
11320
11321 if (!s || s >= e) return 0;
11322
11323 /* remove spaces at head */
11324 if (single_byte_optimizable(str)) {
11325 while (s < e && (*s == '\0' || ascii_isspace(*s))) s++;
11326 }
11327 else {
11328 while (s < e) {
11329 int n;
11330 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11331
11332 if (cc && !rb_isspace(cc)) break;
11333 s += n;
11334 }
11335 }
11336 return s - start;
11337}
11338
11339static long
11340lstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11341 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11342{
11343 const char *const start = s;
11344
11345 if (!s || s >= e) return 0;
11346
11347 /* remove leading characters in the table */
11348 while (s < e) {
11349 int n;
11350 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11351
11352 if (!tr_find(cc, table, del, nodel)) break;
11353 s += n;
11354 }
11355 return s - start;
11356}
11357
11358/*
11359 * call-seq:
11360 * lstrip!(*selectors) -> self or nil
11361 *
11362 * Like String#lstrip, except that:
11363 *
11364 * - Performs stripping in +self+ (not in a copy of +self+).
11365 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11366 *
11367 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11368 */
11369
11370static VALUE
11371rb_str_lstrip_bang(int argc, VALUE *argv, VALUE str)
11372{
11373 rb_encoding *enc;
11374 char *start;
11375 long olen, loffset;
11376
11377 str_modify_keep_cr(str);
11378 enc = STR_ENC_GET(str);
11379 RSTRING_GETMEM(str, start, olen);
11380 if (argc > 0) {
11381 char table[TR_TABLE_SIZE];
11382 VALUE del = 0, nodel = 0;
11383
11384 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11385 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11386 }
11387 else {
11388 loffset = lstrip_offset(str, start, start+olen, enc);
11389 }
11390
11391 if (loffset > 0) {
11392 long len = olen-loffset;
11393 memmove(start, start + loffset, len);
11394 STR_SET_LEN(str, len);
11395 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11396 return str;
11397 }
11398 return Qnil;
11399}
11400
11401
11402/*
11403 * call-seq:
11404 * lstrip(*selectors) -> new_string
11405 *
11406 * Returns a copy of +self+ with leading whitespace removed;
11407 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11408 *
11409 * whitespace = "\x00\t\n\v\f\r "
11410 * s = whitespace + 'abc' + whitespace
11411 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11412 * s.lstrip
11413 * # => "abc\u0000\t\n\v\f\r "
11414 *
11415 * If +selectors+ are given, removes characters of +selectors+ from the beginning of +self+:
11416 *
11417 * s = "---abc+++"
11418 * s.lstrip("-") # => "abc+++"
11419 *
11420 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11421 * and may use any of its valid forms, including negation, ranges, and escapes:
11422 *
11423 * "01234abc56789".lstrip("0-9") # "abc56789"
11424 * "01234abc56789".lstrip("0-9", "^4-6") # "4abc56789"
11425 *
11426 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11427 */
11428
11429static VALUE
11430rb_str_lstrip(int argc, VALUE *argv, VALUE str)
11431{
11432 const char *start;
11433 long len, loffset;
11434
11435 RSTRING_GETMEM(str, start, len);
11436 if (argc > 0) {
11437 char table[TR_TABLE_SIZE];
11438 VALUE del = 0, nodel = 0;
11439
11440 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11441 loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel);
11442 }
11443 else {
11444 loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
11445 }
11446 if (loffset <= 0) return str_duplicate(rb_cString, str);
11447 return rb_str_subseq(str, loffset, len - loffset);
11448}
11449
11450static long
11451rstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11452{
11453 const char *t;
11454
11455 rb_str_check_dummy_enc(enc);
11456 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11457 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11458 }
11459 if (!s || s >= e) return 0;
11460 t = e;
11461
11462 /* remove trailing spaces or '\0's */
11463 if (single_byte_optimizable(str)) {
11464 unsigned char c;
11465 while (s < t && ((c = *(t-1)) == '\0' || ascii_isspace(c))) t--;
11466 }
11467 else {
11468 const char *tp;
11469
11470 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11471 unsigned int c = rb_enc_codepoint(tp, e, enc);
11472 if (c && !rb_isspace(c)) break;
11473 t = tp;
11474 }
11475 }
11476 return e - t;
11477}
11478
11479static long
11480rstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11481 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11482{
11483 const char *t, *tp;
11484
11485 rb_str_check_dummy_enc(enc);
11486 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11487 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11488 }
11489 if (!s || s >= e) return 0;
11490 t = e;
11491
11492 /* remove trailing characters in the table */
11493 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11494 unsigned int c = rb_enc_codepoint(tp, e, enc);
11495 if (!tr_find(c, table, del, nodel)) break;
11496 t = tp;
11497 }
11498
11499 return e - t;
11500}
11501
11502/*
11503 * call-seq:
11504 * rstrip!(*selectors) -> self or nil
11505 *
11506 * Like String#rstrip, except that:
11507 *
11508 * - Performs stripping in +self+ (not in a copy of +self+).
11509 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11510 *
11511 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11512 */
11513
11514static VALUE
11515rb_str_rstrip_bang(int argc, VALUE *argv, VALUE str)
11516{
11517 rb_encoding *enc;
11518 char *start;
11519 long olen, roffset;
11520
11521 str_modify_keep_cr(str);
11522 enc = STR_ENC_GET(str);
11523 RSTRING_GETMEM(str, start, olen);
11524 if (argc > 0) {
11525 char table[TR_TABLE_SIZE];
11526 VALUE del = 0, nodel = 0;
11527
11528 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11529 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11530 }
11531 else {
11532 roffset = rstrip_offset(str, start, start+olen, enc);
11533 }
11534 if (roffset > 0) {
11535 long len = olen - roffset;
11536
11537 STR_SET_LEN(str, len);
11538 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11539 return str;
11540 }
11541 return Qnil;
11542}
11543
11544
11545/*
11546 * call-seq:
11547 * rstrip(*selectors) -> new_string
11548 *
11549 * Returns a copy of +self+ with trailing whitespace removed;
11550 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11551 *
11552 * whitespace = "\x00\t\n\v\f\r "
11553 * s = whitespace + 'abc' + whitespace
11554 * s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11555 * s.rstrip # => "\u0000\t\n\v\f\r abc"
11556 *
11557 * If +selectors+ are given, removes characters of +selectors+ from the end of +self+:
11558 *
11559 * s = "---abc+++"
11560 * s.rstrip("+") # => "---abc"
11561 *
11562 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11563 * and may use any of its valid forms, including negation, ranges, and escapes:
11564 *
11565 * "01234abc56789".rstrip("0-9") # "01234abc"
11566 * "01234abc56789".rstrip("0-9", "^4-6") # "01234abc56"
11567 *
11568 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11569 */
11570
11571static VALUE
11572rb_str_rstrip(int argc, VALUE *argv, VALUE str)
11573{
11574 rb_encoding *enc;
11575 const char *start;
11576 long olen, roffset;
11577
11578 enc = STR_ENC_GET(str);
11579 RSTRING_GETMEM(str, start, olen);
11580 if (argc > 0) {
11581 char table[TR_TABLE_SIZE];
11582 VALUE del = 0, nodel = 0;
11583
11584 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11585 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11586 }
11587 else {
11588 roffset = rstrip_offset(str, start, start+olen, enc);
11589 }
11590 if (roffset <= 0) return str_duplicate(rb_cString, str);
11591 return rb_str_subseq(str, 0, olen-roffset);
11592}
11593
11594
11595/*
11596 * call-seq:
11597 * strip!(*selectors) -> self or nil
11598 *
11599 * Like String#strip, except that:
11600 *
11601 * - Any modifications are made to +self+.
11602 * - Returns +self+ if any modification are made, +nil+ otherwise.
11603 *
11604 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11605 */
11606
11607static VALUE
11608rb_str_strip_bang(int argc, VALUE *argv, VALUE str)
11609{
11610 char *start;
11611 long olen, loffset, roffset;
11612 rb_encoding *enc;
11613
11614 str_modify_keep_cr(str);
11615 enc = STR_ENC_GET(str);
11616 RSTRING_GETMEM(str, start, olen);
11617
11618 if (argc > 0) {
11619 char table[TR_TABLE_SIZE];
11620 VALUE del = 0, nodel = 0;
11621
11622 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11623 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11624 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
11625 }
11626 else {
11627 loffset = lstrip_offset(str, start, start+olen, enc);
11628 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
11629 }
11630
11631 if (loffset > 0 || roffset > 0) {
11632 long len = olen-roffset;
11633 if (loffset > 0) {
11634 len -= loffset;
11635 memmove(start, start + loffset, len);
11636 }
11637 STR_SET_LEN(str, len);
11638 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11639 return str;
11640 }
11641 return Qnil;
11642}
11643
11644
11645/*
11646 * call-seq:
11647 * strip(*selectors) -> new_string
11648 *
11649 * Returns a copy of +self+ with leading and trailing whitespace removed;
11650 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11651 *
11652 * whitespace = "\x00\t\n\v\f\r "
11653 * s = whitespace + 'abc' + whitespace
11654 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11655 * s.strip # => "abc"
11656 *
11657 * If +selectors+ are given, removes characters of +selectors+ from both ends of +self+:
11658 *
11659 * s = "---abc+++"
11660 * s.strip("-+") # => "abc"
11661 * s.strip("+-") # => "abc"
11662 *
11663 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11664 * and may use any of its valid forms, including negation, ranges, and escapes:
11665 *
11666 * "01234abc56789".strip("0-9") # "abc"
11667 * "01234abc56789".strip("0-9", "^4-6") # "4abc56"
11668 *
11669 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11670 */
11671
11672static VALUE
11673rb_str_strip(int argc, VALUE *argv, VALUE str)
11674{
11675 const char *start;
11676 long olen, loffset, roffset;
11677 rb_encoding *enc = STR_ENC_GET(str);
11678
11679 RSTRING_GETMEM(str, start, olen);
11680
11681 if (argc > 0) {
11682 char table[TR_TABLE_SIZE];
11683 VALUE del = 0, nodel = 0;
11684
11685 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11686 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11687 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
11688 }
11689 else {
11690 loffset = lstrip_offset(str, start, start+olen, enc);
11691 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
11692 }
11693
11694 if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
11695 return rb_str_subseq(str, loffset, olen-loffset-roffset);
11696}
11697
11698static VALUE
11699scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
11700{
11701 VALUE result = Qnil;
11702 long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
11703 if (pos >= 0) {
11704 VALUE match = Qnil;
11705 if (BUILTIN_TYPE(pat) == T_STRING) {
11706 end = pos + RSTRING_LEN(pat);
11707 }
11708 else {
11709 match = rb_backref_get();
11710 pos = RMATCH_BEG(match, 0);
11711 end = RMATCH_END(match, 0);
11712 }
11713
11714 if (pos == end) {
11715 rb_encoding *enc = STR_ENC_GET(str);
11716 /*
11717 * Always consume at least one character of the input string
11718 */
11719 if (RSTRING_LEN(str) > end)
11720 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
11721 RSTRING_END(str), enc);
11722 else
11723 *start = end + 1;
11724 }
11725 else {
11726 *start = end;
11727 }
11728
11729 if (NIL_P(match) || RMATCH_NREGS(match) == 1) {
11730 result = rb_str_subseq(str, pos, end - pos);
11731 return result;
11732 }
11733 else {
11734 int num_regs = RMATCH_NREGS(match);
11735 result = rb_ary_new2(num_regs);
11736 for (int i = 1; i < num_regs; i++) {
11737 VALUE s = Qnil;
11738 if (RMATCH_BEG(match, i) >= 0) {
11739 s = rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
11740 }
11741
11742 rb_ary_push(result, s);
11743 }
11744 }
11745
11746 RB_GC_GUARD(match);
11747 }
11748
11749 return result;
11750}
11751
11752
11753/*
11754 * call-seq:
11755 * scan(pattern) -> array_of_results
11756 * scan(pattern) {|result| ... } -> self
11757 *
11758 * :include: doc/string/scan.rdoc
11759 *
11760 */
11761
11762static VALUE
11763rb_str_scan(VALUE str, VALUE pat)
11764{
11765 VALUE result;
11766 long start = 0;
11767 long last = -1, prev = 0;
11768 const char *p = RSTRING_PTR(str);
11769 long len = RSTRING_LEN(str);
11770
11771 pat = get_pat_quoted(pat, 1);
11772 mustnot_broken(str);
11773 if (!rb_block_given_p()) {
11774 VALUE ary = rb_ary_new();
11775
11776 while (!NIL_P(result = scan_once(str, pat, &start, 0))) {
11777 last = prev;
11778 prev = start;
11779 rb_ary_push(ary, result);
11780 }
11781 if (last >= 0) rb_pat_search(pat, str, last, 1);
11782 else rb_backref_set(Qnil);
11783 return ary;
11784 }
11785
11786 while (!NIL_P(result = scan_once(str, pat, &start, 1))) {
11787 last = prev;
11788 prev = start;
11789 rb_yield(result);
11790 str_mod_check(str, p, len);
11791 }
11792 if (last >= 0) rb_pat_search(pat, str, last, 1);
11793 return str;
11794}
11795
11796
11797/*
11798 * call-seq:
11799 * hex -> integer
11800 *
11801 * Interprets the leading substring of +self+ as hexadecimal, possibly signed;
11802 * returns its value as an integer.
11803 *
11804 * The leading substring is interpreted as hexadecimal when it begins with:
11805 *
11806 * - One or more character representing hexadecimal digits
11807 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
11808 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit:
11809 *
11810 * 'f'.hex # => 15
11811 * '11'.hex # => 17
11812 * 'FFF'.hex # => 4095
11813 * 'fffg'.hex # => 4095
11814 * 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not.
11815 * 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not.
11816 * 'deadbeef'.hex # => 3735928559
11817 *
11818 * - <tt>'0x'</tt> or <tt>'0X'</tt>, followed by one or more hexadecimal digits:
11819 *
11820 * '0xfff'.hex # => 4095
11821 * '0xfffg'.hex # => 4095
11822 *
11823 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
11824 *
11825 * '-fff'.hex # => -4095
11826 * '-0xFFF'.hex # => -4095
11827 *
11828 * For any substring not described above, returns zero:
11829 *
11830 * 'xxx'.hex # => 0
11831 * ''.hex # => 0
11832 *
11833 * Note that, unlike #oct, this method interprets only hexadecimal,
11834 * and not binary, octal, or decimal notations:
11835 *
11836 * '0b111'.hex # => 45329
11837 * '0o777'.hex # => 0
11838 * '0d999'.hex # => 55705
11839 *
11840 * Related: See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
11841 */
11842
11843static VALUE
11844rb_str_hex(VALUE str)
11845{
11846 return rb_str_to_inum(str, 16, FALSE);
11847}
11848
11849
11850/*
11851 * call-seq:
11852 * oct -> integer
11853 *
11854 * Interprets the leading substring of +self+ as octal, binary, decimal, or hexadecimal, possibly signed;
11855 * returns their value as an integer.
11856 *
11857 * In brief:
11858 *
11859 * # Interpreted as octal.
11860 * '777'.oct # => 511
11861 * '777x'.oct # => 511
11862 * '0777'.oct # => 511
11863 * '0o777'.oct # => 511
11864 * '-777'.oct # => -511
11865 * # Not interpreted as octal.
11866 * '0b111'.oct # => 7 # Interpreted as binary.
11867 * '0d999'.oct # => 999 # Interpreted as decimal.
11868 * '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
11869 *
11870 * The leading substring is interpreted as octal when it begins with:
11871 *
11872 * - One or more character representing octal digits
11873 * (each in the range <tt>'0'..'7'</tt>);
11874 * the string to be interpreted ends at the first character that does not represent an octal digit:
11875 *
11876 * '7'.oct @ => 7
11877 * '11'.oct # => 9
11878 * '777'.oct # => 511
11879 * '0777'.oct # => 511
11880 * '7778'.oct # => 511
11881 * '777x'.oct # => 511
11882 *
11883 * - <tt>'0o'</tt>, followed by one or more octal digits:
11884 *
11885 * '0o777'.oct # => 511
11886 * '0o7778'.oct # => 511
11887 *
11888 * The leading substring is _not_ interpreted as octal when it begins with:
11889 *
11890 * - <tt>'0b'</tt>, followed by one or more characters representing binary digits
11891 * (each in the range <tt>'0'..'1'</tt>);
11892 * the string to be interpreted ends at the first character that does not represent a binary digit.
11893 * the string is interpreted as binary digits (base 2):
11894 *
11895 * '0b111'.oct # => 7
11896 * '0b1112'.oct # => 7
11897 *
11898 * - <tt>'0d'</tt>, followed by one or more characters representing decimal digits
11899 * (each in the range <tt>'0'..'9'</tt>);
11900 * the string to be interpreted ends at the first character that does not represent a decimal digit.
11901 * the string is interpreted as decimal digits (base 10):
11902 *
11903 * '0d999'.oct # => 999
11904 * '0d999x'.oct # => 999
11905 *
11906 * - <tt>'0x'</tt>, followed by one or more characters representing hexadecimal digits
11907 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
11908 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit.
11909 * the string is interpreted as hexadecimal digits (base 16):
11910 *
11911 * '0xfff'.oct # => 4095
11912 * '0xfffg'.oct # => 4095
11913 *
11914 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
11915 *
11916 * '-777'.oct # => -511
11917 * '-0777'.oct # => -511
11918 * '-0b111'.oct # => -7
11919 * '-0xfff'.oct # => -4095
11920 *
11921 * For any substring not described above, returns zero:
11922 *
11923 * 'foo'.oct # => 0
11924 * ''.oct # => 0
11925 *
11926 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
11927 */
11928
11929static VALUE
11930rb_str_oct(VALUE str)
11931{
11932 return rb_str_to_inum(str, -8, FALSE);
11933}
11934
11935#ifndef HAVE_CRYPT_R
11936# include "ruby/thread_native.h"
11937# include "ruby/atomic.h"
11938
11939static struct {
11940 rb_nativethread_lock_t lock;
11941} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
11942#endif
11943
11944/*
11945 * call-seq:
11946 * crypt(salt_str) -> new_string
11947 *
11948 * Returns the string generated by calling <code>crypt(3)</code>
11949 * standard library function with <code>str</code> and
11950 * <code>salt_str</code>, in this order, as its arguments. Please do
11951 * not use this method any longer. It is legacy; provided only for
11952 * backward compatibility with ruby scripts in earlier days. It is
11953 * bad to use in contemporary programs for several reasons:
11954 *
11955 * * Behaviour of C's <code>crypt(3)</code> depends on the OS it is
11956 * run. The generated string lacks data portability.
11957 *
11958 * * On some OSes such as Mac OS, <code>crypt(3)</code> never fails
11959 * (i.e. silently ends up in unexpected results).
11960 *
11961 * * On some OSes such as Mac OS, <code>crypt(3)</code> is not
11962 * thread safe.
11963 *
11964 * * So-called "traditional" usage of <code>crypt(3)</code> is very
11965 * very very weak. According to its manpage, Linux's traditional
11966 * <code>crypt(3)</code> output has only 2**56 variations; too
11967 * easy to brute force today. And this is the default behaviour.
11968 *
11969 * * In order to make things robust some OSes implement so-called
11970 * "modular" usage. To go through, you have to do a complex
11971 * build-up of the <code>salt_str</code> parameter, by hand.
11972 * Failure in generation of a proper salt string tends not to
11973 * yield any errors; typos in parameters are normally not
11974 * detectable.
11975 *
11976 * * For instance, in the following example, the second invocation
11977 * of String#crypt is wrong; it has a typo in "round=" (lacks
11978 * "s"). However the call does not fail and something unexpected
11979 * is generated.
11980 *
11981 * "foo".crypt("$5$rounds=1000$salt$") # OK, proper usage
11982 * "foo".crypt("$5$round=1000$salt$") # Typo not detected
11983 *
11984 * * Even in the "modular" mode, some hash functions are considered
11985 * archaic and no longer recommended at all; for instance module
11986 * <code>$1$</code> is officially abandoned by its author: see
11987 * http://phk.freebsd.dk/sagas/md5crypt_eol/ . For another
11988 * instance module <code>$3$</code> is considered completely
11989 * broken: see the manpage of FreeBSD.
11990 *
11991 * * On some OS such as Mac OS, there is no modular mode. Yet, as
11992 * written above, <code>crypt(3)</code> on Mac OS never fails.
11993 * This means even if you build up a proper salt string it
11994 * generates a traditional DES hash anyways, and there is no way
11995 * for you to be aware of.
11996 *
11997 * "foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
11998 *
11999 * If for some reason you cannot migrate to other secure contemporary
12000 * password hashing algorithms, install the string-crypt gem and
12001 * <code>require 'string/crypt'</code> to continue using it.
12002 */
12003
12004static VALUE
12005rb_str_crypt(VALUE str, VALUE salt)
12006{
12007#ifdef HAVE_CRYPT_R
12008 VALUE databuf;
12009 struct crypt_data *data;
12010# define CRYPT_END() ALLOCV_END(databuf)
12011#else
12012 char *tmp_buf;
12013 extern char *crypt(const char *, const char *);
12014# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12015#endif
12016 VALUE result;
12017 const char *s, *saltp, *res;
12018#ifdef BROKEN_CRYPT
12019 char salt_8bit_clean[3];
12020#endif
12021
12022 StringValue(salt);
12023 mustnot_wchar(str);
12024 mustnot_wchar(salt);
12025 s = StringValueCStr(str);
12026 saltp = RSTRING_PTR(salt);
12027 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12028 rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
12029 }
12030
12031#ifdef BROKEN_CRYPT
12032 if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) {
12033 salt_8bit_clean[0] = saltp[0] & 0x7f;
12034 salt_8bit_clean[1] = saltp[1] & 0x7f;
12035 salt_8bit_clean[2] = '\0';
12036 saltp = salt_8bit_clean;
12037 }
12038#endif
12039#ifdef HAVE_CRYPT_R
12040 data = ALLOCV(databuf, sizeof(struct crypt_data));
12041# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12042 data->initialized = 0;
12043# endif
12044 res = crypt_r(s, saltp, data);
12045#else
12046 rb_nativethread_lock_lock(&crypt_mutex.lock);
12047 res = crypt(s, saltp);
12048#endif
12049 if (!res) {
12050 int err = errno;
12051 CRYPT_END();
12052 rb_syserr_fail(err, "crypt");
12053 }
12054#ifdef HAVE_CRYPT_R
12055 result = rb_str_new_cstr(res);
12056 CRYPT_END();
12057#else
12058 // We need to copy this buffer because it's static and we need to unlock the mutex
12059 // before allocating a new object (the string to be returned). If we allocate while
12060 // holding the lock, we could run GC which fires the VM barrier and causes a deadlock
12061 // if other ractors are waiting on this lock.
12062 size_t res_size = strlen(res);
12063 tmp_buf = ALLOCA_N(char, res_size); // should be small enough to alloca
12064 memcpy(tmp_buf, res, res_size);
12065 CRYPT_END();
12066 result = rb_str_new(tmp_buf, res_size);
12067#endif
12068 return result;
12069}
12070
12071
12072/*
12073 * call-seq:
12074 * ord -> integer
12075 *
12076 * :include: doc/string/ord.rdoc
12077 *
12078 */
12079
12080static VALUE
12081rb_str_ord(VALUE s)
12082{
12083 unsigned int c;
12084
12085 c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
12086 return UINT2NUM(c);
12087}
12088/*
12089 * call-seq:
12090 * sum(n = 16) -> integer
12091 *
12092 * :include: doc/string/sum.rdoc
12093 *
12094 */
12095
12096static VALUE
12097rb_str_sum(int argc, VALUE *argv, VALUE str)
12098{
12099 int bits = 16;
12100 char *ptr, *p, *pend;
12101 long len;
12102 VALUE sum = INT2FIX(0);
12103 unsigned long sum0 = 0;
12104
12105 if (rb_check_arity(argc, 0, 1) && (bits = NUM2INT(argv[0])) < 0) {
12106 bits = 0;
12107 }
12108 ptr = p = RSTRING_PTR(str);
12109 len = RSTRING_LEN(str);
12110 pend = p + len;
12111
12112 while (p < pend) {
12113 if (FIXNUM_MAX - UCHAR_MAX < sum0) {
12114 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12115 str_mod_check(str, ptr, len);
12116 sum0 = 0;
12117 }
12118 sum0 += (unsigned char)*p;
12119 p++;
12120 }
12121
12122 if (bits == 0) {
12123 if (sum0) {
12124 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12125 }
12126 }
12127 else {
12128 if (sum == INT2FIX(0)) {
12129 if (bits < (int)sizeof(long)*CHAR_BIT) {
12130 sum0 &= (((unsigned long)1)<<bits)-1;
12131 }
12132 sum = LONG2FIX(sum0);
12133 }
12134 else {
12135 VALUE mod;
12136
12137 if (sum0) {
12138 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12139 }
12140
12141 mod = rb_funcall(INT2FIX(1), idLTLT, 1, INT2FIX(bits));
12142 mod = rb_funcall(mod, '-', 1, INT2FIX(1));
12143 sum = rb_funcall(sum, '&', 1, mod);
12144 }
12145 }
12146 return sum;
12147}
12148
12149static VALUE
12150rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
12151{
12152 rb_encoding *enc;
12153 VALUE w;
12154 long width, len, flen = 1, fclen = 1;
12155 VALUE res;
12156 char *p;
12157 const char *f = " ";
12158 long n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12159 VALUE pad;
12160 int singlebyte = 1, cr;
12161 int termlen;
12162
12163 rb_scan_args(argc, argv, "11", &w, &pad);
12164 enc = STR_ENC_GET(str);
12165 width = NUM2LONG(w);
12166 if (argc == 2) {
12167 StringValue(pad);
12168 enc = rb_enc_check(str, pad);
12169 f = RSTRING_PTR(pad);
12170 flen = RSTRING_LEN(pad);
12171 fclen = str_strlen(pad, enc); /* rb_enc_check */
12172 singlebyte = single_byte_optimizable(pad);
12173 if (flen == 0 || fclen == 0) {
12174 rb_raise(rb_eArgError, "zero width padding");
12175 }
12176 }
12177 termlen = rb_enc_mbminlen(enc);
12178 len = str_strlen(str, enc); /* rb_enc_check */
12179 if (width < 0 || len >= width) return str_duplicate(rb_cString, str);
12180 n = width - len;
12181 llen = (jflag == 'l') ? 0 : ((jflag == 'r') ? n : n/2);
12182 rlen = n - llen;
12183 cr = ENC_CODERANGE(str);
12184 if (flen > 1) {
12185 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12186 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12187 }
12188 size = RSTRING_LEN(str);
12189 if ((len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
12190 (len *= flen) >= LONG_MAX - llen2 - rlen2 ||
12191 (len += llen2 + rlen2) >= LONG_MAX - size) {
12192 rb_raise(rb_eArgError, "argument too big");
12193 }
12194 len += size;
12195 res = str_enc_new(rb_cString, 0, len, enc);
12196 p = RSTRING_PTR(res);
12197 if (flen <= 1) {
12198 memset(p, *f, llen);
12199 p += llen;
12200 }
12201 else {
12202 while (llen >= fclen) {
12203 memcpy(p,f,flen);
12204 p += flen;
12205 llen -= fclen;
12206 }
12207 if (llen > 0) {
12208 memcpy(p, f, llen2);
12209 p += llen2;
12210 }
12211 }
12212 memcpy(p, RSTRING_PTR(str), size);
12213 p += size;
12214 if (flen <= 1) {
12215 memset(p, *f, rlen);
12216 p += rlen;
12217 }
12218 else {
12219 while (rlen >= fclen) {
12220 memcpy(p,f,flen);
12221 p += flen;
12222 rlen -= fclen;
12223 }
12224 if (rlen > 0) {
12225 memcpy(p, f, rlen2);
12226 p += rlen2;
12227 }
12228 }
12229 TERM_FILL(p, termlen);
12230 STR_SET_LEN(res, p-RSTRING_PTR(res));
12231
12232 if (argc == 2)
12233 cr = ENC_CODERANGE_AND(cr, ENC_CODERANGE(pad));
12234 if (cr != ENC_CODERANGE_BROKEN)
12235 ENC_CODERANGE_SET(res, cr);
12236
12237 RB_GC_GUARD(pad);
12238 return res;
12239}
12240
12241
12242/*
12243 * call-seq:
12244 * ljust(width, pad_string = ' ') -> new_string
12245 *
12246 * :include: doc/string/ljust.rdoc
12247 *
12248 */
12249
12250static VALUE
12251rb_str_ljust(int argc, VALUE *argv, VALUE str)
12252{
12253 return rb_str_justify(argc, argv, str, 'l');
12254}
12255
12256/*
12257 * call-seq:
12258 * rjust(width, pad_string = ' ') -> new_string
12259 *
12260 * :include: doc/string/rjust.rdoc
12261 *
12262 */
12263
12264static VALUE
12265rb_str_rjust(int argc, VALUE *argv, VALUE str)
12266{
12267 return rb_str_justify(argc, argv, str, 'r');
12268}
12269
12270
12271/*
12272 * call-seq:
12273 * center(size, pad_string = ' ') -> new_string
12274 *
12275 * :include: doc/string/center.rdoc
12276 *
12277 */
12278
12279static VALUE
12280rb_str_center(int argc, VALUE *argv, VALUE str)
12281{
12282 return rb_str_justify(argc, argv, str, 'c');
12283}
12284
12285/*
12286 * call-seq:
12287 * partition(pattern) -> [pre_match, first_match, post_match]
12288 *
12289 * :include: doc/string/partition.rdoc
12290 *
12291 */
12292
12293static VALUE
12294rb_str_partition(VALUE str, VALUE sep)
12295{
12296 long pos;
12297
12298 sep = get_pat_quoted(sep, 0);
12299 if (RB_TYPE_P(sep, T_REGEXP)) {
12300 if (rb_reg_search(sep, str, 0, 0) < 0) {
12301 goto failed;
12302 }
12303 VALUE match = rb_backref_get();
12304
12305 pos = RMATCH_BEG(match, 0);
12306 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12307 }
12308 else {
12309 pos = rb_str_index(str, sep, 0);
12310 if (pos < 0) goto failed;
12311 }
12312 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12313 sep,
12314 rb_str_subseq(str, pos+RSTRING_LEN(sep),
12315 RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
12316
12317 failed:
12318 return rb_ary_new3(3, str_duplicate(rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12319}
12320
12321/*
12322 * call-seq:
12323 * rpartition(pattern) -> [pre_match, last_match, post_match]
12324 *
12325 * :include: doc/string/rpartition.rdoc
12326 *
12327 */
12328
12329static VALUE
12330rb_str_rpartition(VALUE str, VALUE sep)
12331{
12332 long pos = RSTRING_LEN(str);
12333
12334 sep = get_pat_quoted(sep, 0);
12335 if (RB_TYPE_P(sep, T_REGEXP)) {
12336 if (rb_reg_search(sep, str, pos, 1) < 0) {
12337 goto failed;
12338 }
12339 VALUE match = rb_backref_get();
12340
12341 pos = RMATCH_BEG(match, 0);
12342 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12343 }
12344 else {
12345 pos = rb_str_sublen(str, pos);
12346 pos = rb_str_rindex(str, sep, pos);
12347 if (pos < 0) {
12348 goto failed;
12349 }
12350 }
12351
12352 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12353 sep,
12354 rb_str_subseq(str, pos+RSTRING_LEN(sep),
12355 RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
12356 failed:
12357 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(rb_cString, str));
12358}
12359
12360/*
12361 * call-seq:
12362 * start_with?(*patterns) -> true or false
12363 *
12364 * :include: doc/string/start_with_p.rdoc
12365 *
12366 */
12367
12368static VALUE
12369rb_str_start_with(int argc, VALUE *argv, VALUE str)
12370{
12371 int i;
12372
12373 for (i=0; i<argc; i++) {
12374 VALUE tmp = argv[i];
12375 if (RB_TYPE_P(tmp, T_REGEXP)) {
12376 if (rb_reg_start_with_p(tmp, str))
12377 return Qtrue;
12378 }
12379 else {
12380 const char *p, *s, *e;
12381 long slen, tlen;
12382 rb_encoding *enc;
12383
12384 StringValue(tmp);
12385 enc = rb_enc_check(str, tmp);
12386 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12387 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12388 p = RSTRING_PTR(str);
12389 e = p + slen;
12390 s = p + tlen;
12391 if (!at_char_right_boundary(p, s, e, enc))
12392 continue;
12393 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12394 return Qtrue;
12395 }
12396 }
12397 return Qfalse;
12398}
12399
12400/*
12401 * call-seq:
12402 * end_with?(*strings) -> true or false
12403 *
12404 * :include: doc/string/end_with_p.rdoc
12405 *
12406 */
12407
12408static VALUE
12409rb_str_end_with(int argc, VALUE *argv, VALUE str)
12410{
12411 int i;
12412
12413 for (i=0; i<argc; i++) {
12414 VALUE tmp = argv[i];
12415 const char *p, *s, *e;
12416 long slen, tlen;
12417 rb_encoding *enc;
12418
12419 StringValue(tmp);
12420 enc = rb_enc_check(str, tmp);
12421 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12422 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12423 p = RSTRING_PTR(str);
12424 e = p + slen;
12425 s = e - tlen;
12426 if (!at_char_boundary(p, s, e, enc))
12427 continue;
12428 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12429 return Qtrue;
12430 }
12431 return Qfalse;
12432}
12433
12443static long
12444deleted_prefix_length(VALUE str, VALUE prefix)
12445{
12446 const char *strptr, *prefixptr;
12447 long olen, prefixlen;
12448 rb_encoding *enc = rb_enc_get(str);
12449
12450 StringValue(prefix);
12451
12452 if (!is_broken_string(prefix) ||
12453 !rb_enc_asciicompat(enc) ||
12454 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12455 enc = rb_enc_check(str, prefix);
12456 }
12457
12458 /* return 0 if not start with prefix */
12459 prefixlen = RSTRING_LEN(prefix);
12460 if (prefixlen <= 0) return 0;
12461 olen = RSTRING_LEN(str);
12462 if (olen < prefixlen) return 0;
12463 strptr = RSTRING_PTR(str);
12464 prefixptr = RSTRING_PTR(prefix);
12465 if (memcmp(strptr, prefixptr, prefixlen) != 0) return 0;
12466 if (is_broken_string(prefix)) {
12467 if (!is_broken_string(str)) {
12468 /* prefix in a valid string cannot be broken */
12469 return 0;
12470 }
12471 const char *strend = strptr + olen;
12472 const char *after_prefix = strptr + prefixlen;
12473 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12474 /* prefix does not end at char-boundary */
12475 return 0;
12476 }
12477 }
12478 /* prefix part in `str` also should be valid. */
12479
12480 return prefixlen;
12481}
12482
12483/*
12484 * call-seq:
12485 * delete_prefix!(prefix) -> self or nil
12486 *
12487 * Like String#delete_prefix, except that +self+ is modified in place;
12488 * returns +self+ if the prefix is removed, +nil+ otherwise.
12489 *
12490 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12491 */
12492
12493static VALUE
12494rb_str_delete_prefix_bang(VALUE str, VALUE prefix)
12495{
12496 long prefixlen;
12497 str_modify_keep_cr(str);
12498
12499 prefixlen = deleted_prefix_length(str, prefix);
12500 if (prefixlen <= 0) return Qnil;
12501
12502 return rb_str_drop_bytes(str, prefixlen);
12503}
12504
12505/*
12506 * call-seq:
12507 * delete_prefix(prefix) -> new_string
12508 *
12509 * :include: doc/string/delete_prefix.rdoc
12510 *
12511 */
12512
12513static VALUE
12514rb_str_delete_prefix(VALUE str, VALUE prefix)
12515{
12516 long prefixlen;
12517
12518 prefixlen = deleted_prefix_length(str, prefix);
12519 if (prefixlen <= 0) return str_duplicate(rb_cString, str);
12520
12521 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
12522}
12523
12533static long
12534deleted_suffix_length(VALUE str, VALUE suffix)
12535{
12536 const char *strptr, *suffixptr;
12537 long olen, suffixlen;
12538 rb_encoding *enc;
12539
12540 StringValue(suffix);
12541 if (is_broken_string(suffix)) return 0;
12542 enc = rb_enc_check(str, suffix);
12543
12544 /* return 0 if not start with suffix */
12545 suffixlen = RSTRING_LEN(suffix);
12546 if (suffixlen <= 0) return 0;
12547 olen = RSTRING_LEN(str);
12548 if (olen < suffixlen) return 0;
12549 strptr = RSTRING_PTR(str);
12550 suffixptr = RSTRING_PTR(suffix);
12551 const char *strend = strptr + olen;
12552 const char *before_suffix = strend - suffixlen;
12553 if (memcmp(before_suffix, suffixptr, suffixlen) != 0) return 0;
12554 if (!at_char_boundary(strptr, before_suffix, strend, enc)) return 0;
12555
12556 return suffixlen;
12557}
12558
12559/*
12560 * call-seq:
12561 * delete_suffix!(suffix) -> self or nil
12562 *
12563 * Like String#delete_suffix, except that +self+ is modified in place;
12564 * returns +self+ if the suffix is removed, +nil+ otherwise.
12565 *
12566 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12567 */
12568
12569static VALUE
12570rb_str_delete_suffix_bang(VALUE str, VALUE suffix)
12571{
12572 long olen, suffixlen, len;
12573 str_modifiable(str);
12574
12575 suffixlen = deleted_suffix_length(str, suffix);
12576 if (suffixlen <= 0) return Qnil;
12577
12578 olen = RSTRING_LEN(str);
12579 str_modify_keep_cr(str);
12580 len = olen - suffixlen;
12581 STR_SET_LEN(str, len);
12582 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
12583 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
12585 }
12586 return str;
12587}
12588
12589/*
12590 * call-seq:
12591 * delete_suffix(suffix) -> new_string
12592 *
12593 * :include: doc/string/delete_suffix.rdoc
12594 *
12595 */
12596
12597static VALUE
12598rb_str_delete_suffix(VALUE str, VALUE suffix)
12599{
12600 long suffixlen;
12601
12602 suffixlen = deleted_suffix_length(str, suffix);
12603 if (suffixlen <= 0) return str_duplicate(rb_cString, str);
12604
12605 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
12606}
12607
12608void
12609rb_str_setter(VALUE val, ID id, VALUE *var)
12610{
12611 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING)) {
12612 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
12613 }
12614 *var = val;
12615}
12616
12617static void
12618nil_setter_warning(ID id)
12619{
12620 rb_warn_deprecated("non-nil '%"PRIsVALUE"'", NULL, rb_id2str(id));
12621}
12622
12623void
12624rb_deprecated_str_setter(VALUE val, ID id, VALUE *var)
12625{
12626 rb_str_setter(val, id, var);
12627 if (!NIL_P(*var)) {
12628 nil_setter_warning(id);
12629 }
12630}
12631
12632static void
12633rb_fs_setter(VALUE val, ID id, VALUE *var)
12634{
12635 val = rb_fs_check(val);
12636 if (!val) {
12637 rb_raise(rb_eTypeError,
12638 "value of %"PRIsVALUE" must be String or Regexp",
12639 rb_id2str(id));
12640 }
12641 if (!NIL_P(val)) {
12642 nil_setter_warning(id);
12643 }
12644 *var = val;
12645}
12646
12647
12648/*
12649 * call-seq:
12650 * force_encoding(encoding) -> self
12651 *
12652 * :include: doc/string/force_encoding.rdoc
12653 *
12654 */
12655
12656static VALUE
12657rb_str_force_encoding(VALUE str, VALUE enc)
12658{
12659 str_modifiable(str);
12660
12661 rb_encoding *encoding = rb_to_encoding(enc);
12662 int idx = rb_enc_to_index(encoding);
12663
12664 // If the encoding is unchanged, we do nothing.
12665 if (ENCODING_GET(str) == idx) {
12666 return str;
12667 }
12668
12669 rb_enc_associate_index(str, idx);
12670
12671 // If the coderange was 7bit and the new encoding is ASCII-compatible
12672 // we can keep the coderange.
12673 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT && encoding && rb_enc_asciicompat(encoding)) {
12674 return str;
12675 }
12676
12678 return str;
12679}
12680
12681/*
12682 * call-seq:
12683 * b -> new_string
12684 *
12685 * :include: doc/string/b.rdoc
12686 *
12687 */
12688
12689static VALUE
12690rb_str_b(VALUE str)
12691{
12692 VALUE str2;
12693 if (STR_EMBED_P(str)) {
12694 str2 = str_alloc_embed(rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
12695 }
12696 else {
12697 str2 = str_alloc_heap(rb_cString);
12698 }
12699 str_replace_shared_without_enc(str2, str);
12700
12701 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
12702 // BINARY strings can never be broken; they're either 7-bit ASCII or VALID.
12703 // If we know the receiver's code range then we know the result's code range.
12704 int cr = ENC_CODERANGE(str);
12705 switch (cr) {
12706 case ENC_CODERANGE_7BIT:
12708 break;
12712 break;
12713 default:
12714 ENC_CODERANGE_CLEAR(str2);
12715 break;
12716 }
12717 }
12718
12719 return str2;
12720}
12721
12722/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
12723static VALUE
12724rb_str_valid_encoding_p(VALUE str)
12725{
12726 int cr = rb_enc_str_coderange(str);
12727
12728 return RBOOL(cr != ENC_CODERANGE_BROKEN);
12729}
12730
12731/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
12732static VALUE
12733rb_str_is_ascii_only_p(VALUE str)
12734{
12735 int cr = rb_enc_str_coderange(str);
12736
12737 return RBOOL(cr == ENC_CODERANGE_7BIT);
12738}
12739
12740VALUE
12742{
12743 static const char ellipsis[] = "...";
12744 const long ellipsislen = sizeof(ellipsis) - 1;
12745 rb_encoding *const enc = rb_enc_get(str);
12746 const long blen = RSTRING_LEN(str);
12747 const char *const p = RSTRING_PTR(str), *e = p + blen;
12748 VALUE estr, ret = 0;
12749
12750 if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
12751 if (len * rb_enc_mbminlen(enc) >= blen ||
12752 (e = rb_enc_nth(p, e, len, enc)) - p == blen) {
12753 ret = str;
12754 }
12755 else if (len <= ellipsislen ||
12756 !(e = rb_enc_step_back(p, e, e, len = ellipsislen, enc))) {
12757 if (rb_enc_asciicompat(enc)) {
12758 ret = rb_str_new(ellipsis, len);
12759 rb_enc_associate(ret, enc);
12760 }
12761 else {
12762 estr = rb_usascii_str_new(ellipsis, len);
12763 ret = rb_str_encode(estr, rb_enc_from_encoding(enc), 0, Qnil);
12764 }
12765 }
12766 else if (ret = rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
12767 rb_str_cat(ret, ellipsis, ellipsislen);
12768 }
12769 else {
12770 estr = rb_str_encode(rb_usascii_str_new(ellipsis, ellipsislen),
12771 rb_enc_from_encoding(enc), 0, Qnil);
12772 rb_str_append(ret, estr);
12773 }
12774 return ret;
12775}
12776
12777static VALUE
12778str_compat_and_valid(VALUE str, rb_encoding *enc)
12779{
12780 int cr;
12781 str = StringValue(str);
12782 cr = rb_enc_str_coderange(str);
12783 if (cr == ENC_CODERANGE_BROKEN) {
12784 rb_raise(rb_eArgError, "replacement must be valid byte sequence '%+"PRIsVALUE"'", str);
12785 }
12786 else {
12787 rb_encoding *e = STR_ENC_GET(str);
12788 if (cr == ENC_CODERANGE_7BIT ? rb_enc_mbminlen(enc) != 1 : enc != e) {
12789 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
12790 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
12791 }
12792 }
12793 return str;
12794}
12795
12796static VALUE enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr);
12797
12798VALUE
12800{
12801 rb_encoding *enc = STR_ENC_GET(str);
12802 return enc_str_scrub(enc, str, repl, ENC_CODERANGE(str));
12803}
12804
12805VALUE
12806rb_enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl)
12807{
12808 int cr = ENC_CODERANGE_UNKNOWN;
12809 if (enc == STR_ENC_GET(str)) {
12810 /* cached coderange makes sense only when enc equals the
12811 * actual encoding of str */
12812 cr = ENC_CODERANGE(str);
12813 }
12814 return enc_str_scrub(enc, str, repl, cr);
12815}
12816
12817static VALUE
12818enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
12819{
12820 int encidx;
12821 VALUE buf = Qnil;
12822 const char *rep, *p, *e, *p1, *sp;
12823 long replen = -1;
12824 long slen;
12825
12826 if (rb_block_given_p()) {
12827 if (!NIL_P(repl))
12828 rb_raise(rb_eArgError, "both of block and replacement given");
12829 replen = 0;
12830 }
12831
12832 if (ENC_CODERANGE_CLEAN_P(cr))
12833 return Qnil;
12834
12835 if (!NIL_P(repl)) {
12836 repl = str_compat_and_valid(repl, enc);
12837 }
12838
12839 if (rb_enc_dummy_p(enc)) {
12840 return Qnil;
12841 }
12842 encidx = rb_enc_to_index(enc);
12843
12844#define DEFAULT_REPLACE_CHAR(str) do { \
12845 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
12846 rep = replace; replen = (int)sizeof(replace); \
12847 } while (0)
12848
12849 slen = RSTRING_LEN(str);
12850 p = RSTRING_PTR(str);
12851 e = RSTRING_END(str);
12852 p1 = p;
12853 sp = p;
12854
12855 if (rb_enc_asciicompat(enc)) {
12856 int rep7bit_p;
12857 if (!replen) {
12858 rep = NULL;
12859 rep7bit_p = FALSE;
12860 }
12861 else if (!NIL_P(repl)) {
12862 rep = RSTRING_PTR(repl);
12863 replen = RSTRING_LEN(repl);
12864 rep7bit_p = (ENC_CODERANGE(repl) == ENC_CODERANGE_7BIT);
12865 }
12866 else if (encidx == rb_utf8_encindex()) {
12867 DEFAULT_REPLACE_CHAR("\xEF\xBF\xBD");
12868 rep7bit_p = FALSE;
12869 }
12870 else {
12871 DEFAULT_REPLACE_CHAR("?");
12872 rep7bit_p = TRUE;
12873 }
12874 cr = ENC_CODERANGE_7BIT;
12875
12876 p = search_nonascii(p, e);
12877 if (!p) {
12878 p = e;
12879 }
12880 while (p < e) {
12881 int ret = rb_enc_precise_mbclen(p, e, enc);
12882 if (MBCLEN_NEEDMORE_P(ret)) {
12883 break;
12884 }
12885 else if (MBCLEN_CHARFOUND_P(ret)) {
12887 p += MBCLEN_CHARFOUND_LEN(ret);
12888 /* After a multibyte character, fast-skip the following ASCII run. */
12889 p = search_nonascii(p, e);
12890 if (!p) {
12891 p = e;
12892 break;
12893 }
12894 }
12895 else if (MBCLEN_INVALID_P(ret)) {
12896 /*
12897 * p1~p: valid ascii/multibyte chars
12898 * p ~e: invalid bytes + unknown bytes
12899 */
12900 long clen = rb_enc_mbmaxlen(enc);
12901 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
12902 if (p > p1) {
12903 rb_str_buf_cat(buf, p1, p - p1);
12904 }
12905
12906 if (e - p < clen) clen = e - p;
12907 if (clen <= 2) {
12908 clen = 1;
12909 }
12910 else {
12911 const char *q = p;
12912 clen--;
12913 for (; clen > 1; clen--) {
12914 ret = rb_enc_precise_mbclen(q, q + clen, enc);
12915 if (MBCLEN_NEEDMORE_P(ret)) break;
12916 if (MBCLEN_INVALID_P(ret)) continue;
12918 }
12919 }
12920 if (rep) {
12921 rb_str_buf_cat(buf, rep, replen);
12922 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
12923 }
12924 else {
12925 repl = rb_yield(rb_enc_str_new(p, clen, enc));
12926 str_mod_check(str, sp, slen);
12927 repl = str_compat_and_valid(repl, enc);
12928 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
12931 }
12932 p += clen;
12933 p1 = p;
12934 p = search_nonascii(p, e);
12935 if (!p) {
12936 p = e;
12937 break;
12938 }
12939 }
12940 else {
12942 }
12943 }
12944 if (NIL_P(buf)) {
12945 if (p == e) {
12946 ENC_CODERANGE_SET(str, cr);
12947 return Qnil;
12948 }
12949 buf = rb_str_buf_new(RSTRING_LEN(str));
12950 }
12951 if (p1 < p) {
12952 rb_str_buf_cat(buf, p1, p - p1);
12953 }
12954 if (p < e) {
12955 if (rep) {
12956 rb_str_buf_cat(buf, rep, replen);
12957 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
12958 }
12959 else {
12960 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
12961 str_mod_check(str, sp, slen);
12962 repl = str_compat_and_valid(repl, enc);
12963 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
12966 }
12967 }
12968 }
12969 else {
12970 /* ASCII incompatible */
12971 long mbminlen = rb_enc_mbminlen(enc);
12972 if (!replen) {
12973 rep = NULL;
12974 }
12975 else if (!NIL_P(repl)) {
12976 rep = RSTRING_PTR(repl);
12977 replen = RSTRING_LEN(repl);
12978 }
12979 else if (encidx == ENCINDEX_UTF_16BE) {
12980 DEFAULT_REPLACE_CHAR("\xFF\xFD");
12981 }
12982 else if (encidx == ENCINDEX_UTF_16LE) {
12983 DEFAULT_REPLACE_CHAR("\xFD\xFF");
12984 }
12985 else if (encidx == ENCINDEX_UTF_32BE) {
12986 DEFAULT_REPLACE_CHAR("\x00\x00\xFF\xFD");
12987 }
12988 else if (encidx == ENCINDEX_UTF_32LE) {
12989 DEFAULT_REPLACE_CHAR("\xFD\xFF\x00\x00");
12990 }
12991 else {
12992 DEFAULT_REPLACE_CHAR("?");
12993 }
12994
12995 while (p < e) {
12996 int ret = rb_enc_precise_mbclen(p, e, enc);
12997 if (MBCLEN_NEEDMORE_P(ret)) {
12998 break;
12999 }
13000 else if (MBCLEN_CHARFOUND_P(ret)) {
13001 p += MBCLEN_CHARFOUND_LEN(ret);
13002 }
13003 else if (MBCLEN_INVALID_P(ret)) {
13004 const char *q = p;
13005 long clen = rb_enc_mbmaxlen(enc);
13006 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
13007 if (p > p1) rb_str_buf_cat(buf, p1, p - p1);
13008
13009 if (e - p < clen) clen = e - p;
13010 if (clen <= mbminlen * 2) {
13011 clen = mbminlen;
13012 }
13013 else {
13014 clen -= mbminlen;
13015 for (; clen > mbminlen; clen-=mbminlen) {
13016 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13017 if (MBCLEN_NEEDMORE_P(ret)) break;
13018 if (MBCLEN_INVALID_P(ret)) continue;
13020 }
13021 }
13022 if (rep) {
13023 rb_str_buf_cat(buf, rep, replen);
13024 }
13025 else {
13026 repl = rb_yield(rb_enc_str_new(p, clen, enc));
13027 str_mod_check(str, sp, slen);
13028 repl = str_compat_and_valid(repl, enc);
13029 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13030 }
13031 p += clen;
13032 p1 = p;
13033 }
13034 else {
13036 }
13037 }
13038 if (NIL_P(buf)) {
13039 if (p == e) {
13041 return Qnil;
13042 }
13043 buf = rb_str_buf_new(RSTRING_LEN(str));
13044 }
13045 if (p1 < p) {
13046 rb_str_buf_cat(buf, p1, p - p1);
13047 }
13048 if (p < e) {
13049 if (rep) {
13050 rb_str_buf_cat(buf, rep, replen);
13051 }
13052 else {
13053 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
13054 str_mod_check(str, sp, slen);
13055 repl = str_compat_and_valid(repl, enc);
13056 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13057 }
13058 }
13060 }
13061 ENCODING_CODERANGE_SET(buf, rb_enc_to_index(enc), cr);
13062 return buf;
13063}
13064
13065/*
13066 * call-seq:
13067 * scrub(replacement_string = default_replacement_string) -> new_string
13068 * scrub{|sequence| ... } -> new_string
13069 *
13070 * :include: doc/string/scrub.rdoc
13071 *
13072 */
13073static VALUE
13074str_scrub(int argc, VALUE *argv, VALUE str)
13075{
13076 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13077 VALUE new = rb_str_scrub(str, repl);
13078 return NIL_P(new) ? str_duplicate(rb_cString, str): new;
13079}
13080
13081/*
13082 * call-seq:
13083 * scrub!(replacement_string = default_replacement_string) -> self
13084 * scrub!{|sequence| ... } -> self
13085 *
13086 * Like String#scrub, except that:
13087 *
13088 * - Any replacements are made in +self+.
13089 * - Returns +self+.
13090 *
13091 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13092 *
13093 */
13094static VALUE
13095str_scrub_bang(int argc, VALUE *argv, VALUE str)
13096{
13097 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13098 VALUE new = rb_str_scrub(str, repl);
13099 if (!NIL_P(new)) rb_str_replace(str, new);
13100 return str;
13101}
13102
13103static ID id_normalize;
13104static ID id_normalized_p;
13105static VALUE mUnicodeNormalize;
13106
13107static VALUE
13108unicode_normalize_common(int argc, VALUE *argv, VALUE str, ID id)
13109{
13110 static int UnicodeNormalizeRequired = 0;
13111 VALUE argv2[2];
13112
13113 if (!UnicodeNormalizeRequired) {
13114 rb_require("unicode_normalize/normalize.rb");
13115 UnicodeNormalizeRequired = 1;
13116 }
13117 argv2[0] = str;
13118 if (rb_check_arity(argc, 0, 1)) argv2[1] = argv[0];
13119 return rb_funcallv(mUnicodeNormalize, id, argc+1, argv2);
13120}
13121
13122/*
13123 * call-seq:
13124 * unicode_normalize(form = :nfc) -> string
13125 *
13126 * :include: doc/string/unicode_normalize.rdoc
13127 *
13128 */
13129static VALUE
13130rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
13131{
13132 return unicode_normalize_common(argc, argv, str, id_normalize);
13133}
13134
13135/*
13136 * call-seq:
13137 * unicode_normalize!(form = :nfc) -> self
13138 *
13139 * Like String#unicode_normalize, except that the normalization
13140 * is performed on +self+ (not on a copy of +self+).
13141 *
13142 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13143 *
13144 */
13145static VALUE
13146rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
13147{
13148 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13149}
13150
13151/* call-seq:
13152 * unicode_normalized?(form = :nfc) -> true or false
13153 *
13154 * Returns whether +self+ is in the given +form+ of Unicode normalization;
13155 * see String#unicode_normalize.
13156 *
13157 * The +form+ must be one of +:nfc+, +:nfd+, +:nfkc+, or +:nfkd+.
13158 *
13159 * Examples:
13160 *
13161 * "a\u0300".unicode_normalized? # => false
13162 * "a\u0300".unicode_normalized?(:nfd) # => true
13163 * "\u00E0".unicode_normalized? # => true
13164 * "\u00E0".unicode_normalized?(:nfd) # => false
13165 *
13166 *
13167 * Raises an exception if +self+ is not in a Unicode encoding:
13168 *
13169 * s = "\xE0".force_encoding(Encoding::ISO_8859_1)
13170 * s.unicode_normalized? # Raises Encoding::CompatibilityError
13171 *
13172 * Related: see {Querying}[rdoc-ref:String@Querying].
13173 */
13174static VALUE
13175rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
13176{
13177 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13178}
13179
13180/**********************************************************************
13181 * Document-class: Symbol
13182 *
13183 * A +Symbol+ object represents a named identifier inside the Ruby interpreter.
13184 *
13185 * You can create a +Symbol+ object explicitly with:
13186 *
13187 * - A {symbol literal}[rdoc-ref:syntax/literals.rdoc@Symbol+Literals].
13188 *
13189 * The same +Symbol+ object will be
13190 * created for a given name or string for the duration of a program's
13191 * execution, regardless of the context or meaning of that name. Thus
13192 * if <code>Fred</code> is a constant in one context, a method in
13193 * another, and a class in a third, the +Symbol+ <code>:Fred</code>
13194 * will be the same object in all three contexts.
13195 *
13196 * module One
13197 * class Fred
13198 * end
13199 * $f1 = :Fred
13200 * end
13201 * module Two
13202 * Fred = 1
13203 * $f2 = :Fred
13204 * end
13205 * def Fred()
13206 * end
13207 * $f3 = :Fred
13208 * $f1.object_id #=> 2514190
13209 * $f2.object_id #=> 2514190
13210 * $f3.object_id #=> 2514190
13211 *
13212 * Constant, method, and variable names are returned as symbols:
13213 *
13214 * module One
13215 * Two = 2
13216 * def three; 3 end
13217 * @four = 4
13218 * @@five = 5
13219 * $six = 6
13220 * end
13221 * seven = 7
13222 *
13223 * One.constants
13224 * # => [:Two]
13225 * One.instance_methods(true)
13226 * # => [:three]
13227 * One.instance_variables
13228 * # => [:@four]
13229 * One.class_variables
13230 * # => [:@@five]
13231 * global_variables.grep(/six/)
13232 * # => [:$six]
13233 * local_variables
13234 * # => [:seven]
13235 *
13236 * A +Symbol+ object differs from a String object in that
13237 * a +Symbol+ object represents an identifier, while a String object
13238 * represents text or data.
13239 *
13240 * == What's Here
13241 *
13242 * First, what's elsewhere. Class +Symbol+:
13243 *
13244 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
13245 * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
13246 *
13247 * Here, class +Symbol+ provides methods that are useful for:
13248 *
13249 * - {Querying}[rdoc-ref:Symbol@Methods+for+Querying]
13250 * - {Comparing}[rdoc-ref:Symbol@Methods+for+Comparing]
13251 * - {Converting}[rdoc-ref:Symbol@Methods+for+Converting]
13252 *
13253 * === Methods for Querying
13254 *
13255 * - ::all_symbols: Returns an array of the symbols currently in Ruby's symbol table.
13256 * - #=~: Returns the index of the first substring in symbol that matches a
13257 * given Regexp or other object; returns +nil+ if no match is found.
13258 * - #[], #slice : Returns a substring of symbol
13259 * determined by a given index, start/length, or range, or string.
13260 * - #empty?: Returns +true+ if +self.length+ is zero; +false+ otherwise.
13261 * - #encoding: Returns the Encoding object that represents the encoding
13262 * of symbol.
13263 * - #end_with?: Returns +true+ if symbol ends with
13264 * any of the given strings.
13265 * - #match: Returns a MatchData object if symbol
13266 * matches a given Regexp; +nil+ otherwise.
13267 * - #match?: Returns +true+ if symbol
13268 * matches a given Regexp; +false+ otherwise.
13269 * - #length, #size: Returns the number of characters in symbol.
13270 * - #start_with?: Returns +true+ if symbol starts with
13271 * any of the given strings.
13272 *
13273 * === Methods for Comparing
13274 *
13275 * - #<=>: Returns -1, 0, or 1 as a given symbol is smaller than, equal to,
13276 * or larger than symbol.
13277 * - #==, #===: Returns +true+ if a given symbol has the same content and
13278 * encoding.
13279 * - #casecmp: Ignoring case, returns -1, 0, or 1 as a given
13280 * symbol is smaller than, equal to, or larger than symbol.
13281 * - #casecmp?: Returns +true+ if symbol is equal to a given symbol
13282 * after Unicode case folding; +false+ otherwise.
13283 *
13284 * === Methods for Converting
13285 *
13286 * - #capitalize: Returns symbol with the first character upcased
13287 * and all other characters downcased.
13288 * - #downcase: Returns symbol with all characters downcased.
13289 * - #inspect: Returns the string representation of +self+ as a symbol literal.
13290 * - #name: Returns the frozen string corresponding to symbol.
13291 * - #succ, #next: Returns the symbol that is the successor to symbol.
13292 * - #swapcase: Returns symbol with all upcase characters downcased
13293 * and all downcase characters upcased.
13294 * - #to_proc: Returns a Proc object which responds to the method named by symbol.
13295 * - #to_s, #id2name: Returns the string corresponding to +self+.
13296 * - #to_sym, #intern: Returns +self+.
13297 * - #upcase: Returns symbol with all characters upcased.
13298 *
13299 */
13300
13301
13302/*
13303 * call-seq:
13304 * self == other -> true or false
13305 *
13306 * Returns whether +other+ is the same object as +self+.
13307 */
13308
13309#define sym_equal rb_obj_equal
13310
13311static int
13312sym_printable(const char *s, const char *send, rb_encoding *enc)
13313{
13314 while (s < send) {
13315 int n;
13316 int c = rb_enc_precise_mbclen(s, send, enc);
13317
13318 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
13319 n = MBCLEN_CHARFOUND_LEN(c);
13320 c = rb_enc_mbc_to_codepoint(s, send, enc);
13321 if (!rb_enc_isprint(c, enc)) return FALSE;
13322 s += n;
13323 }
13324 return TRUE;
13325}
13326
13327int
13328rb_str_symname_p(VALUE sym)
13329{
13330 rb_encoding *enc;
13331 const char *ptr;
13332 long len;
13333 rb_encoding *resenc = rb_default_internal_encoding();
13334
13335 if (resenc == NULL) resenc = rb_default_external_encoding();
13336 enc = STR_ENC_GET(sym);
13337 ptr = RSTRING_PTR(sym);
13338 len = RSTRING_LEN(sym);
13339 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) || len != (long)strlen(ptr) ||
13340 !rb_enc_symname2_p(ptr, len, enc) || !sym_printable(ptr, ptr + len, enc)) {
13341 return FALSE;
13342 }
13343 return TRUE;
13344}
13345
13346VALUE
13347rb_str_quote_unprintable(VALUE str)
13348{
13349 rb_encoding *enc;
13350 const char *ptr;
13351 long len;
13352 rb_encoding *resenc;
13353
13354 Check_Type(str, T_STRING);
13355 resenc = rb_default_internal_encoding();
13356 if (resenc == NULL) resenc = rb_default_external_encoding();
13357 enc = STR_ENC_GET(str);
13358 ptr = RSTRING_PTR(str);
13359 len = RSTRING_LEN(str);
13360 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13361 !sym_printable(ptr, ptr + len, enc)) {
13362 return rb_str_escape(str);
13363 }
13364 return str;
13365}
13366
13367VALUE
13368rb_id_quote_unprintable(ID id)
13369{
13370 VALUE str = rb_id2str(id);
13371 if (!rb_str_symname_p(str)) {
13372 return rb_str_escape(str);
13373 }
13374 return str;
13375}
13376
13377/*
13378 * call-seq:
13379 * inspect -> string
13380 *
13381 * Returns a string representation of +self+ (including the leading colon):
13382 *
13383 * :foo.inspect # => ":foo"
13384 *
13385 * Related: Symbol#to_s, Symbol#name.
13386 *
13387 */
13388
13389static VALUE
13390sym_inspect(VALUE sym)
13391{
13392 VALUE str = rb_sym2str(sym);
13393 const char *ptr;
13394 long len;
13395 char *dest;
13396
13397 if (!rb_str_symname_p(str)) {
13398 str = rb_str_inspect(str);
13399 len = RSTRING_LEN(str);
13400 rb_str_resize(str, len + 1);
13401 dest = RSTRING_PTR(str);
13402 memmove(dest + 1, dest, len);
13403 }
13404 else {
13405 rb_encoding *enc = STR_ENC_GET(str);
13406 VALUE orig_str = str;
13407
13408 len = RSTRING_LEN(orig_str);
13409 str = rb_enc_str_new(0, len + 1, enc);
13410
13411 // Get data pointer after allocation
13412 ptr = RSTRING_PTR(orig_str);
13413 dest = RSTRING_PTR(str);
13414 memcpy(dest + 1, ptr, len);
13415
13416 RB_GC_GUARD(orig_str);
13417 }
13418 dest[0] = ':';
13419
13421
13422 return str;
13423}
13424
13425VALUE
13427{
13428 return rb_sym2str(sym);
13429}
13430
13431VALUE
13432rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc)
13433{
13434 VALUE obj;
13435
13436 if (argc < 1) {
13437 rb_raise(rb_eArgError, "no receiver given");
13438 }
13439 obj = argv[0];
13440 return rb_funcall_with_block_kw(obj, mid, argc - 1, argv + 1, passed_proc, kw_splat);
13441}
13442
13443/*
13444 * call-seq:
13445 * succ
13446 *
13447 * Equivalent to <tt>self.to_s.succ.to_sym</tt>:
13448 *
13449 * :foo.succ # => :fop
13450 *
13451 * Related: String#succ.
13452 */
13453
13454static VALUE
13455sym_succ(VALUE sym)
13456{
13457 return rb_str_intern(rb_str_succ(rb_sym2str(sym)));
13458}
13459
13460/*
13461 * call-seq:
13462 * self <=> other -> -1, 0, 1, or nil
13463 *
13464 * Compares +self+ and +other+, using String#<=>.
13465 *
13466 * Returns:
13467 *
13468 * - <tt>self.to_s <=> other.to_s</tt>, if +other+ is a symbol.
13469 * - +nil+, otherwise.
13470 *
13471 * Examples:
13472 *
13473 * :bar <=> :foo # => -1
13474 * :foo <=> :foo # => 0
13475 * :foo <=> :bar # => 1
13476 * :foo <=> 'bar' # => nil
13477 *
13478 * \Class \Symbol includes module Comparable,
13479 * each of whose methods uses Symbol#<=> for comparison.
13480 *
13481 * Related: String#<=>.
13482 */
13483
13484static VALUE
13485sym_cmp(VALUE sym, VALUE other)
13486{
13487 if (!SYMBOL_P(other)) {
13488 return Qnil;
13489 }
13490 return rb_str_cmp_m(rb_sym2str(sym), rb_sym2str(other));
13491}
13492
13493/*
13494 * call-seq:
13495 * casecmp(object) -> -1, 0, 1, or nil
13496 *
13497 * :include: doc/symbol/casecmp.rdoc
13498 *
13499 */
13500
13501static VALUE
13502sym_casecmp(VALUE sym, VALUE other)
13503{
13504 if (!SYMBOL_P(other)) {
13505 return Qnil;
13506 }
13507 return str_casecmp(rb_sym2str(sym), rb_sym2str(other));
13508}
13509
13510/*
13511 * call-seq:
13512 * casecmp?(object) -> true, false, or nil
13513 *
13514 * :include: doc/symbol/casecmp_p.rdoc
13515 *
13516 */
13517
13518static VALUE
13519sym_casecmp_p(VALUE sym, VALUE other)
13520{
13521 if (!SYMBOL_P(other)) {
13522 return Qnil;
13523 }
13524 return str_casecmp_p(rb_sym2str(sym), rb_sym2str(other));
13525}
13526
13527/*
13528 * call-seq:
13529 * self =~ other -> integer or nil
13530 *
13531 * Equivalent to <tt>self.to_s =~ other</tt>,
13532 * including possible updates to global variables;
13533 * see String#=~.
13534 *
13535 */
13536
13537static VALUE
13538sym_match(VALUE sym, VALUE other)
13539{
13540 return rb_str_match(rb_sym2str(sym), other);
13541}
13542
13543/*
13544 * call-seq:
13545 * match(pattern, offset = 0) -> matchdata or nil
13546 * match(pattern, offset = 0) {|matchdata| } -> object
13547 *
13548 * Equivalent to <tt>self.to_s.match</tt>,
13549 * including possible updates to global variables;
13550 * see String#match.
13551 *
13552 */
13553
13554static VALUE
13555sym_match_m(int argc, VALUE *argv, VALUE sym)
13556{
13557 return rb_str_match_m(argc, argv, rb_sym2str(sym));
13558}
13559
13560/*
13561 * call-seq:
13562 * match?(pattern, offset) -> true or false
13563 *
13564 * Equivalent to <tt>sym.to_s.match?</tt>;
13565 * see String#match.
13566 *
13567 */
13568
13569static VALUE
13570sym_match_m_p(int argc, VALUE *argv, VALUE sym)
13571{
13572 return rb_str_match_m_p(argc, argv, sym);
13573}
13574
13575/*
13576 * call-seq:
13577 * self[offset] -> string or nil
13578 * self[offset, size] -> string or nil
13579 * self[range] -> string or nil
13580 * self[regexp, capture = 0] -> string or nil
13581 * self[substring] -> string or nil
13582 *
13583 * Equivalent to <tt>symbol.to_s[]</tt>; see String#[].
13584 *
13585 */
13586
13587static VALUE
13588sym_aref(int argc, VALUE *argv, VALUE sym)
13589{
13590 return rb_str_aref_m(argc, argv, rb_sym2str(sym));
13591}
13592
13593/*
13594 * call-seq:
13595 * length -> integer
13596 *
13597 * Equivalent to <tt>self.to_s.length</tt>; see String#length.
13598 */
13599
13600static VALUE
13601sym_length(VALUE sym)
13602{
13603 return rb_str_length(rb_sym2str(sym));
13604}
13605
13606/*
13607 * call-seq:
13608 * upcase(mapping) -> symbol
13609 *
13610 * Equivalent to <tt>sym.to_s.upcase.to_sym</tt>.
13611 *
13612 * See String#upcase.
13613 *
13614 */
13615
13616static VALUE
13617sym_upcase(int argc, VALUE *argv, VALUE sym)
13618{
13619 return rb_str_intern(rb_str_upcase(argc, argv, rb_sym2str(sym)));
13620}
13621
13622/*
13623 * call-seq:
13624 * downcase(mapping) -> symbol
13625 *
13626 * Equivalent to <tt>sym.to_s.downcase.to_sym</tt>.
13627 *
13628 * See String#downcase.
13629 *
13630 * Related: Symbol#upcase.
13631 *
13632 */
13633
13634static VALUE
13635sym_downcase(int argc, VALUE *argv, VALUE sym)
13636{
13637 return rb_str_intern(rb_str_downcase(argc, argv, rb_sym2str(sym)));
13638}
13639
13640/*
13641 * call-seq:
13642 * capitalize(mapping) -> symbol
13643 *
13644 * Equivalent to <tt>sym.to_s.capitalize.to_sym</tt>.
13645 *
13646 * See String#capitalize.
13647 *
13648 */
13649
13650static VALUE
13651sym_capitalize(int argc, VALUE *argv, VALUE sym)
13652{
13653 return rb_str_intern(rb_str_capitalize(argc, argv, rb_sym2str(sym)));
13654}
13655
13656/*
13657 * call-seq:
13658 * swapcase(mapping) -> symbol
13659 *
13660 * Equivalent to <tt>sym.to_s.swapcase.to_sym</tt>.
13661 *
13662 * See String#swapcase.
13663 *
13664 */
13665
13666static VALUE
13667sym_swapcase(int argc, VALUE *argv, VALUE sym)
13668{
13669 return rb_str_intern(rb_str_swapcase(argc, argv, rb_sym2str(sym)));
13670}
13671
13672/*
13673 * call-seq:
13674 * start_with?(*string_or_regexp) -> true or false
13675 *
13676 * Equivalent to <tt>self.to_s.start_with?</tt>; see String#start_with?.
13677 *
13678 */
13679
13680static VALUE
13681sym_start_with(int argc, VALUE *argv, VALUE sym)
13682{
13683 return rb_str_start_with(argc, argv, rb_sym2str(sym));
13684}
13685
13686/*
13687 * call-seq:
13688 * end_with?(*strings) -> true or false
13689 *
13690 *
13691 * Equivalent to <tt>self.to_s.end_with?</tt>; see String#end_with?.
13692 *
13693 */
13694
13695static VALUE
13696sym_end_with(int argc, VALUE *argv, VALUE sym)
13697{
13698 return rb_str_end_with(argc, argv, rb_sym2str(sym));
13699}
13700
13701/*
13702 * call-seq:
13703 * encoding -> encoding
13704 *
13705 * Equivalent to <tt>self.to_s.encoding</tt>; see String#encoding.
13706 *
13707 */
13708
13709static VALUE
13710sym_encoding(VALUE sym)
13711{
13712 return rb_obj_encoding(rb_sym2str(sym));
13713}
13714
13715static VALUE
13716string_for_symbol(VALUE name)
13717{
13718 if (!RB_TYPE_P(name, T_STRING)) {
13719 VALUE tmp = rb_check_string_type(name);
13720 if (NIL_P(tmp)) {
13721 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
13722 name);
13723 }
13724 name = tmp;
13725 }
13726 return name;
13727}
13728
13729ID
13731{
13732 if (SYMBOL_P(name)) {
13733 return SYM2ID(name);
13734 }
13735 name = string_for_symbol(name);
13736 return rb_intern_str(name);
13737}
13738
13739VALUE
13741{
13742 if (SYMBOL_P(name)) {
13743 return name;
13744 }
13745 name = string_for_symbol(name);
13746 return rb_str_intern(name);
13747}
13748
13749/*
13750 * call-seq:
13751 * Symbol.all_symbols -> array_of_symbols
13752 *
13753 * Returns an array of all symbols currently in Ruby's symbol table:
13754 *
13755 * Symbol.all_symbols.size # => 9334
13756 * Symbol.all_symbols.take(3) # => [:!, :"\"", :"#"]
13757 *
13758 */
13759
13760static VALUE
13761sym_all_symbols(VALUE _)
13762{
13763 return rb_sym_all_symbols();
13764}
13765
13766VALUE
13767rb_str_to_interned_str(VALUE str)
13768{
13769 return rb_fstring(str);
13770}
13771
13772VALUE
13773rb_interned_str(const char *ptr, long len)
13774{
13775 struct RString fake_str = {RBASIC_INIT};
13776 int encidx = ENCINDEX_US_ASCII;
13777 int coderange = ENC_CODERANGE_7BIT;
13778 if (len > 0 && search_nonascii(ptr, ptr + len)) {
13779 encidx = ENCINDEX_ASCII_8BIT;
13780 coderange = ENC_CODERANGE_VALID;
13781 }
13782 VALUE str = setup_fake_str(&fake_str, ptr, len, encidx);
13783 ENC_CODERANGE_SET(str, coderange);
13784 return register_fstring(str, true, false);
13785}
13786
13787VALUE
13789{
13790 return rb_interned_str(ptr, strlen(ptr));
13791}
13792
13793VALUE
13794rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
13795{
13796 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
13797 rb_enc_autoload(enc);
13798 }
13799
13800 struct RString fake_str = {RBASIC_INIT};
13801 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, false);
13802}
13803
13804VALUE
13805rb_enc_literal_str(const char *ptr, long len, rb_encoding *enc)
13806{
13807 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
13808 rb_enc_autoload(enc);
13809 }
13810
13811 struct RString fake_str = {RBASIC_INIT};
13812 VALUE str = register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true);
13813 RUBY_ASSERT(RB_OBJ_SHAREABLE_P(str) && (rb_gc_verify_shareable(str), 1));
13814 return str;
13815}
13816
13817VALUE
13819{
13820 return rb_enc_interned_str(ptr, strlen(ptr), enc);
13821}
13822
13823#if USE_YJIT || USE_ZJIT
13824void
13825rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint)
13826{
13827 if (RB_LIKELY(ENCODING_GET_INLINED(str) == rb_ascii8bit_encindex())) {
13828 ssize_t code = RB_NUM2SSIZE(codepoint);
13829
13830 if (RB_LIKELY(code >= 0 && code < 0xff)) {
13831 rb_str_buf_cat_byte(str, (char) code);
13832 return;
13833 }
13834 }
13835
13836 rb_str_concat(str, codepoint);
13837}
13838#endif
13839
13840static int
13841fstring_set_class_i(VALUE *str, void *data)
13842{
13843 RBASIC_SET_CLASS(*str, rb_cString);
13844
13845 return ST_CONTINUE;
13846}
13847
13848void
13849Init_String(void)
13850{
13851 rb_cString = rb_define_class("String", rb_cObject);
13852
13853 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
13854
13856 rb_define_alloc_func(rb_cString, empty_str_alloc);
13857 rb_define_singleton_method(rb_cString, "new", rb_str_s_new, -1);
13858 rb_define_singleton_method(rb_cString, "try_convert", rb_str_s_try_convert, 1);
13859 rb_define_method(rb_cString, "initialize", rb_str_init, -1);
13861 rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1);
13862 rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
13865 rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
13866 rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
13867 rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
13868 rb_define_method(rb_cString, "casecmp?", rb_str_casecmp_p, 1);
13871 rb_define_method(rb_cString, "%", rb_str_format_m, 1);
13872 rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
13873 rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
13874 rb_define_method(rb_cString, "insert", rb_str_insert, 2);
13877 rb_define_method(rb_cString, "bytesize", rb_str_bytesize, 0);
13878 rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
13879 rb_define_method(rb_cString, "=~", rb_str_match, 1);
13880 rb_define_method(rb_cString, "match", rb_str_match_m, -1);
13881 rb_define_method(rb_cString, "match?", rb_str_match_m_p, -1);
13883 rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0);
13885 rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0);
13886 rb_define_method(rb_cString, "upto", rb_str_upto, -1);
13887 rb_define_method(rb_cString, "index", rb_str_index_m, -1);
13888 rb_define_method(rb_cString, "byteindex", rb_str_byteindex_m, -1);
13889 rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1);
13890 rb_define_method(rb_cString, "byterindex", rb_str_byterindex_m, -1);
13891 rb_define_method(rb_cString, "clear", rb_str_clear, 0);
13892 rb_define_method(rb_cString, "chr", rb_str_chr, 0);
13893 rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
13894 rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);
13895 rb_define_method(rb_cString, "bit_get", rb_str_bit_get, -1);
13896 rb_define_method(rb_cString, "bit_set?", rb_str_bit_set_p, -1);
13897 rb_define_method(rb_cString, "bit_set", rb_str_bit_set, -1);
13898 rb_define_method(rb_cString, "bit_clear", rb_str_bit_clear, -1);
13899 rb_define_method(rb_cString, "bit_flip", rb_str_bit_flip, -1);
13900 rb_define_method(rb_cString, "bit_count", rb_str_bit_count, 0);
13901 rb_define_method(rb_cString, "bitwise_not", rb_str_bitwise_not, 0);
13902 rb_define_method(rb_cString, "bitwise_not!", rb_str_bitwise_not_bang, 0);
13903 rb_define_method(rb_cString, "bitwise_and", rb_str_bitwise_and, 1);
13904 rb_define_method(rb_cString, "bitwise_and!", rb_str_bitwise_and_bang, 1);
13905 rb_define_method(rb_cString, "bitwise_or", rb_str_bitwise_or, 1);
13906 rb_define_method(rb_cString, "bitwise_or!", rb_str_bitwise_or_bang, 1);
13907 rb_define_method(rb_cString, "bitwise_xor", rb_str_bitwise_xor, 1);
13908 rb_define_method(rb_cString, "bitwise_xor!", rb_str_bitwise_xor_bang, 1);
13909 rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);
13910 rb_define_method(rb_cString, "bytesplice", rb_str_bytesplice, -1);
13911 rb_define_method(rb_cString, "scrub", str_scrub, -1);
13912 rb_define_method(rb_cString, "scrub!", str_scrub_bang, -1);
13914 rb_define_method(rb_cString, "+@", str_uplus, 0);
13915 rb_define_method(rb_cString, "-@", str_uminus, 0);
13916 rb_define_method(rb_cString, "dup", rb_str_dup_m, 0);
13917 rb_define_alias(rb_cString, "dedup", "-@");
13918
13919 rb_define_method(rb_cString, "to_i", rb_str_to_i, -1);
13920 rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);
13921 rb_define_method(rb_cString, "to_s", rb_str_to_s, 0);
13922 rb_define_method(rb_cString, "to_str", rb_str_to_s, 0);
13925 rb_define_method(rb_cString, "undump", str_undump, 0);
13926
13927 sym_ascii = ID2SYM(rb_intern_const("ascii"));
13928 sym_turkic = ID2SYM(rb_intern_const("turkic"));
13929 sym_lithuanian = ID2SYM(rb_intern_const("lithuanian"));
13930 sym_fold = ID2SYM(rb_intern_const("fold"));
13931
13932 rb_define_method(rb_cString, "upcase", rb_str_upcase, -1);
13933 rb_define_method(rb_cString, "downcase", rb_str_downcase, -1);
13934 rb_define_method(rb_cString, "capitalize", rb_str_capitalize, -1);
13935 rb_define_method(rb_cString, "swapcase", rb_str_swapcase, -1);
13936
13937 rb_define_method(rb_cString, "upcase!", rb_str_upcase_bang, -1);
13938 rb_define_method(rb_cString, "downcase!", rb_str_downcase_bang, -1);
13939 rb_define_method(rb_cString, "capitalize!", rb_str_capitalize_bang, -1);
13940 rb_define_method(rb_cString, "swapcase!", rb_str_swapcase_bang, -1);
13941
13942 rb_define_method(rb_cString, "hex", rb_str_hex, 0);
13943 rb_define_method(rb_cString, "oct", rb_str_oct, 0);
13944 rb_define_method(rb_cString, "split", rb_str_split_m, -1);
13945 rb_define_method(rb_cString, "lines", rb_str_lines, -1);
13946 rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
13947 rb_define_method(rb_cString, "chars", rb_str_chars, 0);
13948 rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
13949 rb_define_method(rb_cString, "grapheme_clusters", rb_str_grapheme_clusters, 0);
13950 rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
13951 rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
13952 rb_define_method(rb_cString, "concat", rb_str_concat_multi, -1);
13953 rb_define_method(rb_cString, "append_as_bytes", rb_str_append_as_bytes, -1);
13955 rb_define_method(rb_cString, "prepend", rb_str_prepend_multi, -1);
13956 rb_define_method(rb_cString, "crypt", rb_str_crypt, 1);
13957 rb_define_method(rb_cString, "intern", rb_str_intern, 0); /* in symbol.c */
13958 rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); /* in symbol.c */
13959 rb_define_method(rb_cString, "ord", rb_str_ord, 0);
13960
13961 rb_define_method(rb_cString, "include?", rb_str_include, 1);
13962 rb_define_method(rb_cString, "start_with?", rb_str_start_with, -1);
13963 rb_define_method(rb_cString, "end_with?", rb_str_end_with, -1);
13964
13965 rb_define_method(rb_cString, "scan", rb_str_scan, 1);
13966
13967 rb_define_method(rb_cString, "ljust", rb_str_ljust, -1);
13968 rb_define_method(rb_cString, "rjust", rb_str_rjust, -1);
13969 rb_define_method(rb_cString, "center", rb_str_center, -1);
13970
13971 rb_define_method(rb_cString, "sub", rb_str_sub, -1);
13972 rb_define_method(rb_cString, "gsub", rb_str_gsub, -1);
13973 rb_define_method(rb_cString, "chop", rb_str_chop, 0);
13974 rb_define_method(rb_cString, "chomp", rb_str_chomp, -1);
13975 rb_define_method(rb_cString, "strip", rb_str_strip, -1);
13976 rb_define_method(rb_cString, "lstrip", rb_str_lstrip, -1);
13977 rb_define_method(rb_cString, "rstrip", rb_str_rstrip, -1);
13978 rb_define_method(rb_cString, "delete_prefix", rb_str_delete_prefix, 1);
13979 rb_define_method(rb_cString, "delete_suffix", rb_str_delete_suffix, 1);
13980
13981 rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1);
13982 rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1);
13983 rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0);
13984 rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1);
13985 rb_define_method(rb_cString, "strip!", rb_str_strip_bang, -1);
13986 rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, -1);
13987 rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, -1);
13988 rb_define_method(rb_cString, "delete_prefix!", rb_str_delete_prefix_bang, 1);
13989 rb_define_method(rb_cString, "delete_suffix!", rb_str_delete_suffix_bang, 1);
13990
13991 rb_define_method(rb_cString, "tr", rb_str_tr, -1);
13992 rb_define_method(rb_cString, "tr_s", rb_str_tr_s, 2);
13993 rb_define_method(rb_cString, "delete", rb_str_delete, -1);
13994 rb_define_method(rb_cString, "squeeze", rb_str_squeeze, -1);
13995 rb_define_method(rb_cString, "count", rb_str_count, -1);
13996
13997 rb_define_method(rb_cString, "tr!", rb_str_tr_bang, -1);
13998 rb_define_method(rb_cString, "tr_s!", rb_str_tr_s_bang, 2);
13999 rb_define_method(rb_cString, "delete!", rb_str_delete_bang, -1);
14000 rb_define_method(rb_cString, "squeeze!", rb_str_squeeze_bang, -1);
14001
14002 rb_define_method(rb_cString, "each_line", rb_str_each_line, -1);
14003 rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0);
14004 rb_define_method(rb_cString, "each_char", rb_str_each_char, 0);
14005 rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0);
14006 rb_define_method(rb_cString, "each_grapheme_cluster", rb_str_each_grapheme_cluster, 0);
14007
14008 rb_define_method(rb_cString, "sum", rb_str_sum, -1);
14009
14010 rb_define_method(rb_cString, "slice", rb_str_aref_m, -1);
14011 rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1);
14012
14013 rb_define_method(rb_cString, "partition", rb_str_partition, 1);
14014 rb_define_method(rb_cString, "rpartition", rb_str_rpartition, 1);
14015
14016 rb_define_method(rb_cString, "encoding", rb_obj_encoding, 0); /* in encoding.c */
14017 rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1);
14018 rb_define_method(rb_cString, "b", rb_str_b, 0);
14019
14020 /* define UnicodeNormalize module here so that we don't have to look it up */
14021 mUnicodeNormalize = rb_define_module("UnicodeNormalize");
14022 id_normalize = rb_intern_const("normalize");
14023 id_normalized_p = rb_intern_const("normalized?");
14024
14025 rb_define_method(rb_cString, "unicode_normalize", rb_str_unicode_normalize, -1);
14026 rb_define_method(rb_cString, "unicode_normalize!", rb_str_unicode_normalize_bang, -1);
14027 rb_define_method(rb_cString, "unicode_normalized?", rb_str_unicode_normalized_p, -1);
14028
14029 rb_fs = Qnil;
14030 rb_define_hooked_variable("$;", &rb_fs, 0, rb_fs_setter);
14031 rb_define_hooked_variable("$-F", &rb_fs, 0, rb_fs_setter);
14032 rb_gc_register_address(&rb_fs);
14033
14034 rb_cSymbol = rb_define_class("Symbol", rb_cObject);
14038 rb_define_singleton_method(rb_cSymbol, "all_symbols", sym_all_symbols, 0);
14039
14040 rb_define_method(rb_cSymbol, "==", sym_equal, 1);
14041 rb_define_method(rb_cSymbol, "===", sym_equal, 1);
14042 rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
14043 rb_define_method(rb_cSymbol, "to_proc", rb_sym_to_proc, 0); /* in proc.c */
14044 rb_define_method(rb_cSymbol, "succ", sym_succ, 0);
14045 rb_define_method(rb_cSymbol, "next", sym_succ, 0);
14046
14047 rb_define_method(rb_cSymbol, "<=>", sym_cmp, 1);
14048 rb_define_method(rb_cSymbol, "casecmp", sym_casecmp, 1);
14049 rb_define_method(rb_cSymbol, "casecmp?", sym_casecmp_p, 1);
14050 rb_define_method(rb_cSymbol, "=~", sym_match, 1);
14051
14052 rb_define_method(rb_cSymbol, "[]", sym_aref, -1);
14053 rb_define_method(rb_cSymbol, "slice", sym_aref, -1);
14054 rb_define_method(rb_cSymbol, "length", sym_length, 0);
14055 rb_define_method(rb_cSymbol, "size", sym_length, 0);
14056 rb_define_method(rb_cSymbol, "match", sym_match_m, -1);
14057 rb_define_method(rb_cSymbol, "match?", sym_match_m_p, -1);
14058
14059 rb_define_method(rb_cSymbol, "upcase", sym_upcase, -1);
14060 rb_define_method(rb_cSymbol, "downcase", sym_downcase, -1);
14061 rb_define_method(rb_cSymbol, "capitalize", sym_capitalize, -1);
14062 rb_define_method(rb_cSymbol, "swapcase", sym_swapcase, -1);
14063
14064 rb_define_method(rb_cSymbol, "start_with?", sym_start_with, -1);
14065 rb_define_method(rb_cSymbol, "end_with?", sym_end_with, -1);
14066
14067 rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0);
14068}
14069
14070#include "string.rbinc"
#define RUBY_ASSERT_ALWAYS(expr,...)
A variant of RUBY_ASSERT that does not interface with RUBY_DEBUG.
Definition assert.h:199
#define RBIMPL_ASSERT_OR_ASSUME(...)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
Definition assert.h:311
#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.
Definition assert.h:291
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
Atomic operations.
@ RUBY_ENC_CODERANGE_7BIT
The object holds 0 to 127 inclusive and nothing else.
Definition coderange.h:39
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.
Definition coderange.h:162
static int rb_isspace(int c)
Our own locale-insensitive version of isspace(3).
Definition ctype.h:395
static int rb_isascii(int c)
Our own locale-insensitive version of isascii(3).
Definition ctype.h:209
#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.
Definition ctype.h:43
static bool rb_enc_isprint(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isprint(), except it additionally takes an encoding.
Definition ctype.h:180
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.
Definition ctype.h:63
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
Definition sprintf.c:1209
static VALUE RB_OBJ_FROZEN_RAW(VALUE obj)
This is an implementation detail of RB_OBJ_FROZEN().
Definition fl_type.h:696
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
Definition fl_type.h:404
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1609
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2913
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2723
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.
Definition class.c:3203
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1033
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2992
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define ENCODING_SET_INLINED(obj, i)
Old name of RB_ENCODING_SET_INLINED.
Definition encoding.h:106
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define FL_UNSET_RAW
Old name of RB_FL_UNSET_RAW.
Definition fl_type.h:130
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1683
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define ISSPACE
Old name of rb_isspace.
Definition ctype.h:88
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define ENC_CODERANGE_CLEAN_P(cr)
Old name of RB_ENC_CODERANGE_CLEAN_P.
Definition coderange.h:183
#define ENC_CODERANGE_AND(a, b)
Old name of RB_ENC_CODERANGE_AND.
Definition coderange.h:188
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:133
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define ENC_CODERANGE(obj)
Old name of RB_ENC_CODERANGE.
Definition coderange.h:184
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
Definition coderange.h:179
#define SIZET2NUM
Old name of RB_SIZE2NUM.
Definition size_t.h:62
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define ISDIGIT
Old name of rb_isdigit.
Definition ctype.h:93
#define ENC_CODERANGE_MASK
Old name of RUBY_ENC_CODERANGE_MASK.
Definition coderange.h:178
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:128
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:125
#define rb_ary_new3
Old name of rb_ary_new_from_args.
Definition array.h:658
#define ENCODING_INLINE_MAX
Old name of RUBY_ENCODING_INLINE_MAX.
Definition encoding.h:67
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define FL_ANY_RAW
Old name of RB_FL_ANY_RAW.
Definition fl_type.h:122
#define ISALPHA
Old name of rb_isalpha.
Definition ctype.h:92
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ULL2NUM
Old name of RB_ULL2NUM.
Definition long_long.h:31
#define TOLOWER
Old name of rb_tolower.
Definition ctype.h:101
#define Qtrue
Old name of RUBY_Qtrue.
#define ST2FIX
Old name of RB_ST2FIX.
Definition st_data_t.h:33
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define FIXNUM_MAX
Old name of RUBY_FIXNUM_MAX.
Definition fixnum.h:26
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define scan_hex(s, l, e)
Old name of ruby_scan_hex.
Definition util.h:108
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2ULL
Old name of RB_NUM2ULL.
Definition long_long.h:35
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define ISPRINT
Old name of rb_isprint.
Definition ctype.h:86
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define ENCODING_SHIFT
Old name of RUBY_ENCODING_SHIFT.
Definition encoding.h:68
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:127
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:65
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define ENCODING_GET_INLINED(obj)
Old name of RB_ENCODING_GET_INLINED.
Definition encoding.h:108
#define ENC_CODERANGE_CLEAR(obj)
Old name of RB_ENC_CODERANGE_CLEAR.
Definition coderange.h:187
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:129
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define ENCODING_IS_ASCII8BIT(obj)
Old name of RB_ENCODING_IS_ASCII8BIT.
Definition encoding.h:110
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define ENCODING_CODERANGE_SET(obj, encindex, cr)
Old name of RB_ENCODING_CODERANGE_SET.
Definition coderange.h:189
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
Definition fl_type.h:126
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define OBJ_FROZEN_RAW
Old name of RB_OBJ_FROZEN_RAW.
Definition fl_type.h:134
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ENCODING_MASK
Old name of RUBY_ENCODING_MASK.
Definition encoding.h:69
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:478
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:676
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4042
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1435
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
Definition error.c:1438
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:657
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2250
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:94
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 ...
Definition object.c:2268
VALUE rb_obj_frozen_p(VALUE obj)
Just calls RB_OBJ_FROZEN() inside.
Definition object.c:1320
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.
Definition object.c:3640
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:555
VALUE rb_cSymbol
Symbol class.
Definition string.c:86
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:140
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1308
VALUE rb_mComparable
Comparable module.
Definition compar.c:19
VALUE rb_cString
String class.
Definition string.c:85
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3326
Encoding relates APIs.
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.
Definition encoding.h:683
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.
Definition encoding.h:704
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.
Definition encoding.h:571
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:447
static int RB_ENCODING_GET_INLINED(VALUE obj)
Queries the encoding of the passed object.
Definition encoding.h:99
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.
Definition encoding.h:619
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.
Definition encoding.h:726
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1379
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.
Definition string.c:1244
char * rb_enc_nth(const char *head, const char *tail, long nth, rb_encoding *enc)
Queries the n-th character.
Definition string.c:3108
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.
Definition string.c:1263
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.
Definition string.c:13794
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.
Definition re.c:285
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.
Definition string.c:2390
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.
Definition string.c:3833
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.
Definition string.c:1175
VALUE rb_str_export_to_enc(VALUE obj, rb_encoding *enc)
Identical to rb_str_export(), except it additionally takes an encoding.
Definition string.c:1484
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.
Definition string.c:1385
int rb_enc_str_asciionly_p(VALUE str)
Queries if the passed string is "ASCII only".
Definition string.c:988
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.
Definition string.c:13818
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.
Definition string.c:844
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.
Definition symbol.c:858
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.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
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.
Definition transcode.c:2715
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.
Definition transcode.c:2978
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1742
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1123
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.
Definition vm_eval.c:1081
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...
Definition vm_eval.c:1210
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?.
Definition enumerator.h:208
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Definition error.h:35
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_fs
The field separator character for inputs, or the $;.
Definition string.c:723
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:209
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
Definition vm.c:2107
VALUE rb_sym_all_symbols(void)
Collects every single bits of symbols that have ever interned in the entire history of the current pr...
Definition symbol.c:1215
void rb_backref_set(VALUE md)
Updates $~.
Definition vm.c:2113
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
Definition range.c:1970
int rb_reg_backref_number(VALUE match, VALUE backref)
Queries the index of the given named capture.
Definition re.c:1387
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4476
VALUE rb_reg_match(VALUE re, VALUE str)
This is the match operator.
Definition re.c:3970
void rb_match_busy(VALUE md)
Asserts that the given MatchData is "occupied".
Definition re.c:1631
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
Definition re.c:2071
void rb_str_free(VALUE str)
Destroys the given string for no reason.
Definition string.c:1789
VALUE rb_str_new_shared(VALUE str)
Identical to rb_str_new_cstr(), except it takes a Ruby's string instead of C's.
Definition string.c:1549
VALUE rb_str_plus(VALUE lhs, VALUE rhs)
Generates a new string, concatenating the former to the latter.
Definition string.c:2541
#define rb_utf8_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "UTF-8" encoding.
Definition string.h:1584
#define rb_hash_end(h)
Just another name of st_hash_end.
Definition string.h:946
#define rb_hash_uint32(h, i)
Just another name of st_hash_uint32.
Definition string.h:940
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3898
VALUE rb_filesystem_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "filesystem" encoding.
Definition string.c:1460
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
Definition string.c:13426
VALUE rb_str_times(VALUE str, VALUE num)
Repetition of a string.
Definition string.c:2615
VALUE rb_external_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "default external" encoding.
Definition string.c:1436
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1783
long rb_str_offset(VALUE str, long pos)
"Inverse" of rb_str_sublen().
Definition string.c:3136
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
Definition string.c:5437
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4261
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...
Definition string.c:3251
VALUE rb_str_ellipsize(VALUE str, long len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
Definition string.c:12741
st_index_t rb_memhash(const void *ptr, long len)
This is a universal hash function.
Definition random.c:1720
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
void rb_str_shared_replace(VALUE dst, VALUE src)
Replaces the contents of the former with the latter.
Definition string.c:1825
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
VALUE rb_str_new_static(const char *ptr, long len)
Identical to rb_str_new(), except it takes a C string literal.
Definition string.c:1209
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1023
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1555
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2023
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4247
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3666
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.
Definition string.c:2477
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...
Definition string.c:2041
#define rb_str_buf_new_cstr(str)
Identical to rb_str_new_cstr, except done differently.
Definition string.h:1640
#define rb_usascii_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "US ASCII" encoding.
Definition string.h:1568
VALUE rb_str_replace(VALUE dst, VALUE src)
Replaces the contents of the former object with the stringised contents of the latter.
Definition string.c:6648
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.
Definition string.c:3259
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1147
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.
Definition string.c:13788
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...
Definition string.c:1466
#define rb_external_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "default external" encoding.
Definition string.h:1605
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.
Definition string.c:3864
long rb_str_sublen(VALUE str, long pos)
Byte offset to character offset conversion.
Definition string.c:3183
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4368
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3485
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:7825
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2847
VALUE rb_interned_str(const char *ptr, long len)
Identical to rb_str_new(), except it returns an infamous "f"string.
Definition string.c:13773
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4315
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:4135
int rb_str_comparable(VALUE str1, VALUE str2)
Checks if two strings are comparable each other or not.
Definition string.c:4290
#define rb_strlen_lit(str)
Length of a string literal.
Definition string.h:1693
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 ...
Definition string.c:3840
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3376
void rb_str_update(VALUE dst, long beg, long len, VALUE src)
Replaces some (or all) of the contents of the given string.
Definition string.c:5924
VALUE rb_str_scrub(VALUE str, VALUE repl)
"Cleanses" the string.
Definition string.c:12799
#define rb_locale_str_new_cstr(str)
Identical to rb_external_str_new_cstr, except it generates a string of "locale" encoding instead of "...
Definition string.h:1626
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.
Definition string.c:1739
#define rb_str_dup_frozen
Just another name of rb_str_new_frozen.
Definition string.h:632
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3032
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3348
#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.
Definition string.h:1657
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3467
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...
Definition string.c:1238
#define rb_utf8_str_new(str, len)
Identical to rb_str_new, except it generates a string of "UTF-8" encoding.
Definition string.h:1550
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2801
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
Definition string.c:7942
VALUE rb_locale_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "locale" encoding.
Definition string.c:1448
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1755
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
Definition string.c:2491
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_str_drop_bytes(VALUE str, long len)
Shrinks the given string for the given number of bytes.
Definition string.c:5839
VALUE rb_str_split(VALUE str, const char *delim)
Divides the given string based on the given delimiter.
Definition string.c:10435
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...
Definition string.c:1232
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:1085
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1887
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.
Definition variable.c:2060
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
Definition variable.c:2120
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3590
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1809
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().
Definition symbol.h:285
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
Definition string.c:13740
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...
Definition string.c:13730
int capa
Designed capacity of the buffer.
Definition io.h:11
int off
Offset inside of ptr.
Definition io.h:5
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
long rb_reg_search(VALUE re, VALUE str, long pos, int dir)
Runs the passed regular expression over the passed string.
Definition re.c:2000
VALUE rb_reg_regcomp(VALUE str)
Creates a new instance of rb_cRegexp.
Definition re.c:3675
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt)
Formats a string.
Definition sprintf.c:227
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1378
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
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.
Definition rarray.h:280
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:102
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
VALUE rb_str_export_locale(VALUE obj)
Identical to rb_str_export(), except it converts into the locale encoding instead.
Definition string.c:1478
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...
Definition string.c:3003
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
VALUE rb_string_value(volatile VALUE *ptr)
Identical to rb_str_to_str(), except it fills the passed pointer with the converted object.
Definition string.c:2866
#define RSTRING(obj)
Convenient casting macro.
Definition rstring.h:41
VALUE rb_str_export(VALUE obj)
Identical to rb_str_to_str(), except it additionally converts the string into default external encodi...
Definition string.c:1472
char * rb_string_value_ptr(volatile VALUE *ptr)
Identical to rb_str_to_str(), except it returns the converted string's backend memory region.
Definition string.c:2879
VALUE rb_str_to_str(VALUE obj)
Identical to rb_check_string_type(), except it raises exceptions in case of conversion failures.
Definition string.c:1816
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
Definition rtypeddata.h:435
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:557
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition load.c:1490
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_NUM2SSIZE
Converts an instance of rb_cInteger into C's ssize_t.
Definition size_t.h:49
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
VALUE flags
Per-object flags.
Definition rbasic.h:81
Ruby's String.
Definition rstring.h:196
struct RBasic basic
Basic part, including flags and class.
Definition rstring.h:199
union RString::@60::@61::@63 aux
Auxiliary info.
long capa
Capacity of *ptr.
Definition rstring.h:232
long len
Length of the string, not including terminating NUL character.
Definition rstring.h:206
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.
Definition rstring.h:240
char * ptr
Pointer to the contents of the string.
Definition rstring.h:222
union RString::@60 as
String's specific fields.
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:238
Definition string.c:8866
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Blocks until the current thread obtains a lock.
Definition thread.c:317
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static enum ruby_value_type rb_type(VALUE obj)
Identical to RB_BUILTIN_TYPE(), except it can also accept special constants.
Definition value_type.h:225
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:425
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
ruby_value_type
C-level type of an object.
Definition value_type.h:113