Ruby 4.1.0dev (2026-09-16 revision a590a7051f104b488ed31cd27f6548404ce73996)
string.c (a590a7051f104b488ed31cd27f6548404ce73996)
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)) {
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)) {
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 (s + slen <= e && 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 (hit + slen <= e && 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 /* character counts, so the byte tail can still be shorter than sub */
4887 if (len - pos < slen) pos = len - slen;
4888 if (len == 0) return pos;
4889
4890 sbeg = RSTRING_PTR(str);
4891
4892 if (pos == 0) {
4893 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4894 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4895 return 0;
4896 }
4897 else {
4898 return -1;
4899 }
4900 }
4901
4902 s = str_nth(sbeg, RSTRING_END(str), pos, enc, singlebyte);
4903 return str_rindex(str, sub, s, enc);
4904}
4905
4906/*
4907 * call-seq:
4908 * rindex(pattern, offset = self.length) -> integer or nil
4909 *
4910 * :include:doc/string/rindex.rdoc
4911 *
4912 */
4913
4914static VALUE
4915rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
4916{
4917 VALUE sub;
4918 VALUE initpos;
4919 rb_encoding *enc = STR_ENC_GET(str);
4920 long pos, len = str_strlen(str, enc); /* str's enc */
4921
4922 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4923 pos = NUM2LONG(initpos);
4924 if (pos < 0 && (pos += len) < 0) {
4925 if (RB_TYPE_P(sub, T_REGEXP)) {
4927 }
4928 return Qnil;
4929 }
4930 if (pos > len) pos = len;
4931 }
4932 else {
4933 pos = len;
4934 }
4935
4936 if (RB_TYPE_P(sub, T_REGEXP)) {
4937 /* enc = rb_enc_check(str, sub); */
4938 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4939 enc, single_byte_optimizable(str));
4940
4941 if (rb_reg_search(sub, str, pos, 1) >= 0) {
4942 VALUE match = rb_backref_get();
4943 pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
4944 return LONG2NUM(pos);
4945 }
4946 }
4947 else {
4948 StringValue(sub);
4949 pos = rb_str_rindex(str, sub, pos);
4950 if (pos >= 0) {
4951 pos = rb_str_sublen(str, pos);
4952 return LONG2NUM(pos);
4953 }
4954 }
4955 return Qnil;
4956}
4957
4958static long
4959rb_str_byterindex(VALUE str, VALUE sub, long pos)
4960{
4961 long len, slen;
4962 const char *sbeg, *s;
4963 rb_encoding *enc;
4964
4965 enc = rb_enc_check(str, sub);
4966 if (is_broken_string(sub)) return -1;
4967 len = RSTRING_LEN(str);
4968 slen = RSTRING_LEN(sub);
4969
4970 /* substring longer than string */
4971 if (len < slen) return -1;
4972 if (len - pos < slen) pos = len - slen;
4973 if (len == 0) return pos;
4974
4975 sbeg = RSTRING_PTR(str);
4976
4977 if (pos == 0) {
4978 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4979 return 0;
4980 else
4981 return -1;
4982 }
4983
4984 s = sbeg + pos;
4985 return str_rindex(str, sub, s, enc);
4986}
4987
4988/*
4989 * call-seq:
4990 * byterindex(object, offset = self.bytesize) -> integer or nil
4991 *
4992 * Returns the 0-based integer index of a substring of +self+
4993 * that is the _last_ match for the given +object+ (a string or Regexp) and +offset+,
4994 * or +nil+ if there is no such substring;
4995 * the returned index is the count of _bytes_ (not characters).
4996 *
4997 * When +object+ is a string,
4998 * returns the index of the _last_ found substring equal to +object+:
4999 *
5000 * s = 'foo' # => "foo"
5001 * s.size # => 3 # Three 1-byte characters.
5002 * s.bytesize # => 3 # Three bytes.
5003 * s.byterindex('f') # => 0
5004 * s.byterindex('o') # => 2
5005 * s.byterindex('oo') # => 1
5006 * s.byterindex('ooo') # => nil
5007 *
5008 * When +object+ is a Regexp,
5009 * returns the index of the last found substring matching +object+;
5010 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
5011 *
5012 * s = 'foo'
5013 * s.byterindex(/f/) # => 0
5014 * $~ # => #<MatchData "f">
5015 * s.byterindex(/o/) # => 2
5016 * s.byterindex(/oo/) # => 1
5017 * s.byterindex(/ooo/) # => nil
5018 * $~ # => nil
5019 *
5020 * The last match means starting at the possible last position,
5021 * not the last of the longest matches:
5022 *
5023 * s = 'foo'
5024 * s.byterindex(/o+/) # => 2
5025 * $~ #=> #<MatchData "o">
5026 *
5027 * To get the last longest match, use a negative lookbehind:
5028 *
5029 * s = 'foo'
5030 * s.byterindex(/(?<!o)o+/) # => 1
5031 * $~ # => #<MatchData "oo">
5032 *
5033 * Or use method #byteindex with negative lookahead:
5034 *
5035 * s = 'foo'
5036 * s.byteindex(/o+(?!.*o)/) # => 1
5037 * $~ #=> #<MatchData "oo">
5038 *
5039 * \Integer argument +offset+, if given, specifies the 0-based index
5040 * of the byte where searching is to end.
5041 *
5042 * When +offset+ is non-negative,
5043 * searching ends at byte position +offset+:
5044 *
5045 * s = 'foo'
5046 * s.byterindex('o', 0) # => nil
5047 * s.byterindex('o', 1) # => 1
5048 * s.byterindex('o', 2) # => 2
5049 * s.byterindex('o', 3) # => 2
5050 *
5051 * When +offset+ is negative, counts backward from the end of +self+:
5052 *
5053 * s = 'foo'
5054 * s.byterindex('o', -1) # => 2
5055 * s.byterindex('o', -2) # => 1
5056 * s.byterindex('o', -3) # => nil
5057 *
5058 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
5059 *
5060 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
5061 * s.size # => 2 # Two 3-byte characters.
5062 * s.bytesize # => 6 # Six bytes.
5063 * s.byterindex("\uFFFF") # => 3
5064 * s.byterindex("\uFFFF", 1) # Raises IndexError
5065 * s.byterindex("\uFFFF", 2) # Raises IndexError
5066 * s.byterindex("\uFFFF", 3) # => 3
5067 * s.byterindex("\uFFFF", 4) # Raises IndexError
5068 * s.byterindex("\uFFFF", 5) # Raises IndexError
5069 * s.byterindex("\uFFFF", 6) # => nil
5070 *
5071 * Related: see {Querying}[rdoc-ref:String@Querying].
5072 */
5073
5074static VALUE
5075rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
5076{
5077 VALUE sub;
5078 VALUE initpos;
5079 long pos, len = RSTRING_LEN(str);
5080
5081 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
5082 pos = NUM2LONG(initpos);
5083 if (pos < 0 && (pos += len) < 0) {
5084 if (RB_TYPE_P(sub, T_REGEXP)) {
5086 }
5087 return Qnil;
5088 }
5089 if (pos > len) pos = len;
5090 }
5091 else {
5092 pos = len;
5093 }
5094
5095 str_ensure_byte_pos(str, pos);
5096
5097 if (RB_TYPE_P(sub, T_REGEXP)) {
5098 if (rb_reg_search(sub, str, pos, 1) >= 0) {
5099 VALUE match = rb_backref_get();
5100 pos = RMATCH_BEG(match, 0);
5101 return LONG2NUM(pos);
5102 }
5103 }
5104 else {
5105 StringValue(sub);
5106 pos = rb_str_byterindex(str, sub, pos);
5107 if (pos >= 0) return LONG2NUM(pos);
5108 }
5109 return Qnil;
5110}
5111
5112/*
5113 * call-seq:
5114 * self =~ other -> integer or nil
5115 *
5116 * When +other+ is a Regexp:
5117 *
5118 * - Returns the integer index (in characters) of the first match
5119 * for +self+ and +other+, or +nil+ if none;
5120 * - Updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
5121 *
5122 * Examples:
5123 *
5124 * 'foo' =~ /f/ # => 0
5125 * $~ # => #<MatchData "f">
5126 * 'foo' =~ /o/ # => 1
5127 * $~ # => #<MatchData "o">
5128 * 'foo' =~ /x/ # => nil
5129 * $~ # => nil
5130 *
5131 * Note that <tt>string =~ regexp</tt> is different from <tt>regexp =~ string</tt>
5132 * (see Regexp#=~):
5133 *
5134 * number = nil
5135 * 'no. 9' =~ /(?<number>\d+)/ # => 4
5136 * number # => nil # Not assigned.
5137 * /(?<number>\d+)/ =~ 'no. 9' # => 4
5138 * number # => "9" # Assigned.
5139 *
5140 * When +other+ is not a Regexp, returns the value
5141 * returned by <tt>other =~ self</tt>.
5142 *
5143 * Related: see {Querying}[rdoc-ref:String@Querying].
5144 */
5145
5146static VALUE
5147rb_str_match(VALUE x, VALUE y)
5148{
5149 switch (OBJ_BUILTIN_TYPE(y)) {
5150 case T_STRING:
5151 rb_raise(rb_eTypeError, "type mismatch: String given");
5152
5153 case T_REGEXP:
5154 return rb_reg_match(y, x);
5155
5156 default:
5157 return rb_funcall(y, idEqTilde, 1, x);
5158 }
5159}
5160
5161
5162static VALUE get_pat(VALUE);
5163
5164
5165/*
5166 * call-seq:
5167 * match(pattern, offset = 0) -> matchdata or nil
5168 * match(pattern, offset = 0) {|matchdata| ... } -> object
5169 *
5170 * Creates a MatchData object based on +self+ and the given arguments;
5171 * updates {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5172 *
5173 * - Computes +regexp+ by converting +pattern+ (if not already a Regexp).
5174 *
5175 * regexp = Regexp.new(pattern)
5176 *
5177 * - Calls <tt>regexp.match</tt> with +self+ to compute +matchdata+.
5178 * If +offset+ is given, it is also passed (see Regexp#match).
5179 *
5180 * With no block given, returns the computed +matchdata+ or +nil+:
5181 *
5182 * 'foo'.match('f') # => #<MatchData "f">
5183 * 'foo'.match('o') # => #<MatchData "o">
5184 * 'foo'.match('x') # => nil
5185 * 'foo'.match('f', 1) # => nil
5186 * 'foo'.match('o', 1) # => #<MatchData "o">
5187 *
5188 * With a block given and computed +matchdata+ non-nil, calls the block with +matchdata+;
5189 * returns the block's return value:
5190 *
5191 * 'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
5192 *
5193 * With a block given and +nil+ +matchdata+, does not call the block:
5194 *
5195 * 'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => nil
5196 *
5197 * Related: see {Querying}[rdoc-ref:String@Querying].
5198 */
5199
5200static VALUE
5201rb_str_match_m(int argc, VALUE *argv, VALUE str)
5202{
5203 VALUE re, result;
5204 if (argc < 1)
5205 rb_check_arity(argc, 1, 2);
5206 re = argv[0];
5207 argv[0] = str;
5208 result = rb_funcallv(get_pat(re), rb_intern("match"), argc, argv);
5209 if (!NIL_P(result) && rb_block_given_p()) {
5210 return rb_yield(result);
5211 }
5212 return result;
5213}
5214
5215/*
5216 * call-seq:
5217 * match?(pattern, offset = 0) -> true or false
5218 *
5219 * Returns whether a match is found for +self+ and the given arguments;
5220 * does not update {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5221 *
5222 * Computes +regexp+ by converting +pattern+ (if not already a Regexp):
5223 *
5224 * regexp = Regexp.new(pattern)
5225 *
5226 * The search for +regexp+ in +self+ begins at the given character +offset+.
5227 * Returns +true+ if a match is found, +false+ otherwise:
5228 *
5229 * 'foo'.match?(/o/) # => true
5230 * 'foo'.match?('o') # => true
5231 * 'foo'.match?(/x/) # => false
5232 * 'foo'.match?('f', 1) # => false
5233 * 'foo'.match?('o', 1) # => true
5234 *
5235 * Related: see {Querying}[rdoc-ref:String@Querying].
5236 */
5237
5238static VALUE
5239rb_str_match_m_p(int argc, VALUE *argv, VALUE str)
5240{
5241 VALUE re;
5242 rb_check_arity(argc, 1, 2);
5243 re = get_pat(argv[0]);
5244 return rb_reg_match_p(re, str, argc > 1 ? NUM2LONG(argv[1]) : 0);
5245}
5246
5247enum neighbor_char {
5248 NEIGHBOR_NOT_CHAR,
5249 NEIGHBOR_FOUND,
5250 NEIGHBOR_WRAPPED
5251};
5252
5253static enum neighbor_char
5254enc_succ_char(char *p, long len, rb_encoding *enc)
5255{
5256 long i;
5257 int l;
5258
5259 if (rb_enc_mbminlen(enc) > 1) {
5260 /* wchar, trivial case */
5261 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5262 if (!MBCLEN_CHARFOUND_P(r)) {
5263 return NEIGHBOR_NOT_CHAR;
5264 }
5265 c = rb_enc_mbc_to_codepoint(p, p + len, enc) + 1;
5266 l = rb_enc_code_to_mbclen(c, enc);
5267 if (!l) return NEIGHBOR_NOT_CHAR;
5268 if (l != len) return NEIGHBOR_WRAPPED;
5269 rb_enc_mbcput(c, p, enc);
5270 r = rb_enc_precise_mbclen(p, p + len, enc);
5271 if (!MBCLEN_CHARFOUND_P(r)) {
5272 return NEIGHBOR_NOT_CHAR;
5273 }
5274 return NEIGHBOR_FOUND;
5275 }
5276 while (1) {
5277 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0xff; i--)
5278 p[i] = '\0';
5279 if (i < 0)
5280 return NEIGHBOR_WRAPPED;
5281 ++((unsigned char*)p)[i];
5282 l = rb_enc_precise_mbclen(p, p+len, enc);
5283 if (MBCLEN_CHARFOUND_P(l)) {
5284 l = MBCLEN_CHARFOUND_LEN(l);
5285 if (l == len) {
5286 return NEIGHBOR_FOUND;
5287 }
5288 else {
5289 memset(p+l, 0xff, len-l);
5290 }
5291 }
5292 if (MBCLEN_INVALID_P(l) && i < len-1) {
5293 long len2;
5294 int l2;
5295 for (len2 = len-1; 0 < len2; len2--) {
5296 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5297 if (!MBCLEN_INVALID_P(l2))
5298 break;
5299 }
5300 memset(p+len2+1, 0xff, len-(len2+1));
5301 }
5302 }
5303}
5304
5305static enum neighbor_char
5306enc_pred_char(char *p, long len, rb_encoding *enc)
5307{
5308 long i;
5309 int l;
5310 if (rb_enc_mbminlen(enc) > 1) {
5311 /* wchar, trivial case */
5312 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5313 if (!MBCLEN_CHARFOUND_P(r)) {
5314 return NEIGHBOR_NOT_CHAR;
5315 }
5316 c = rb_enc_mbc_to_codepoint(p, p + len, enc);
5317 if (!c) return NEIGHBOR_NOT_CHAR;
5318 --c;
5319 l = rb_enc_code_to_mbclen(c, enc);
5320 if (!l) return NEIGHBOR_NOT_CHAR;
5321 if (l != len) return NEIGHBOR_WRAPPED;
5322 rb_enc_mbcput(c, p, enc);
5323 r = rb_enc_precise_mbclen(p, p + len, enc);
5324 if (!MBCLEN_CHARFOUND_P(r)) {
5325 return NEIGHBOR_NOT_CHAR;
5326 }
5327 return NEIGHBOR_FOUND;
5328 }
5329 while (1) {
5330 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0; i--)
5331 p[i] = '\xff';
5332 if (i < 0)
5333 return NEIGHBOR_WRAPPED;
5334 --((unsigned char*)p)[i];
5335 l = rb_enc_precise_mbclen(p, p+len, enc);
5336 if (MBCLEN_CHARFOUND_P(l)) {
5337 l = MBCLEN_CHARFOUND_LEN(l);
5338 if (l == len) {
5339 return NEIGHBOR_FOUND;
5340 }
5341 else {
5342 memset(p+l, 0, len-l);
5343 }
5344 }
5345 if (MBCLEN_INVALID_P(l) && i < len-1) {
5346 long len2;
5347 int l2;
5348 for (len2 = len-1; 0 < len2; len2--) {
5349 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5350 if (!MBCLEN_INVALID_P(l2))
5351 break;
5352 }
5353 memset(p+len2+1, 0, len-(len2+1));
5354 }
5355 }
5356}
5357
5358/*
5359 overwrite +p+ by succeeding letter in +enc+ and returns
5360 NEIGHBOR_FOUND or NEIGHBOR_WRAPPED.
5361 When NEIGHBOR_WRAPPED, carried-out letter is stored into carry.
5362 assuming each ranges are successive, and mbclen
5363 never change in each ranges.
5364 NEIGHBOR_NOT_CHAR is returned if invalid character or the range has only one
5365 character.
5366 */
5367static enum neighbor_char
5368enc_succ_alnum_char(char *p, long len, rb_encoding *enc, char *carry)
5369{
5370 enum neighbor_char ret;
5371 unsigned int c;
5372 int ctype;
5373 int range;
5374 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5375
5376 /* skip 03A2, invalid char between GREEK CAPITAL LETTERS */
5377 int try;
5378 const int max_gaps = 1;
5379
5380 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5381 if (rb_enc_isctype(c, ONIGENC_CTYPE_DIGIT, enc))
5382 ctype = ONIGENC_CTYPE_DIGIT;
5383 else if (rb_enc_isctype(c, ONIGENC_CTYPE_ALPHA, enc))
5384 ctype = ONIGENC_CTYPE_ALPHA;
5385 else
5386 return NEIGHBOR_NOT_CHAR;
5387
5388 MEMCPY(save, p, char, len);
5389 for (try = 0; try <= max_gaps; ++try) {
5390 ret = enc_succ_char(p, len, enc);
5391 if (ret == NEIGHBOR_FOUND) {
5392 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5393 if (rb_enc_isctype(c, ctype, enc))
5394 return NEIGHBOR_FOUND;
5395 }
5396 }
5397 MEMCPY(p, save, char, len);
5398 range = 1;
5399 while (1) {
5400 MEMCPY(save, p, char, len);
5401 ret = enc_pred_char(p, len, enc);
5402 if (ret == NEIGHBOR_FOUND) {
5403 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5404 if (!rb_enc_isctype(c, ctype, enc)) {
5405 MEMCPY(p, save, char, len);
5406 break;
5407 }
5408 }
5409 else {
5410 MEMCPY(p, save, char, len);
5411 break;
5412 }
5413 range++;
5414 }
5415 if (range == 1) {
5416 return NEIGHBOR_NOT_CHAR;
5417 }
5418
5419 if (ctype != ONIGENC_CTYPE_DIGIT) {
5420 MEMCPY(carry, p, char, len);
5421 return NEIGHBOR_WRAPPED;
5422 }
5423
5424 MEMCPY(carry, p, char, len);
5425 enc_succ_char(carry, len, enc);
5426 return NEIGHBOR_WRAPPED;
5427}
5428
5429
5430static VALUE str_succ(VALUE str);
5431
5432/*
5433 * call-seq:
5434 * succ -> new_str
5435 *
5436 * :include: doc/string/succ.rdoc
5437 *
5438 */
5439
5440VALUE
5442{
5443 VALUE str;
5444 str = rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5445 rb_enc_cr_str_copy_for_substr(str, orig);
5446 return str_succ(str);
5447}
5448
5449static VALUE
5450str_succ(VALUE str)
5451{
5452 rb_encoding *enc;
5453 char *sbeg, *s, *e, *last_alnum = 0;
5454 int found_alnum = 0;
5455 long l, slen;
5456 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] = "\1";
5457 long carry_pos = 0, carry_len = 1;
5458 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5459
5460 slen = RSTRING_LEN(str);
5461 if (slen == 0) return str;
5462
5463 enc = STR_ENC_GET(str);
5464 sbeg = RSTRING_PTR(str);
5465 s = e = sbeg + slen;
5466
5467 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5468 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5469 if (ISALPHA(*last_alnum) ? ISDIGIT(*s) :
5470 ISDIGIT(*last_alnum) ? ISALPHA(*s) : 0) {
5471 break;
5472 }
5473 }
5474 l = rb_enc_precise_mbclen(s, e, enc);
5475 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5476 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5477 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5478 switch (neighbor) {
5479 case NEIGHBOR_NOT_CHAR:
5480 continue;
5481 case NEIGHBOR_FOUND:
5482 return str;
5483 case NEIGHBOR_WRAPPED:
5484 last_alnum = s;
5485 break;
5486 }
5487 found_alnum = 1;
5488 carry_pos = s - sbeg;
5489 carry_len = l;
5490 }
5491 if (!found_alnum) { /* str contains no alnum */
5492 s = e;
5493 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5494 enum neighbor_char neighbor;
5495 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5496 l = rb_enc_precise_mbclen(s, e, enc);
5497 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5498 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5499 MEMCPY(tmp, s, char, l);
5500 neighbor = enc_succ_char(tmp, l, enc);
5501 switch (neighbor) {
5502 case NEIGHBOR_FOUND:
5503 MEMCPY(s, tmp, char, l);
5504 return str;
5505 break;
5506 case NEIGHBOR_WRAPPED:
5507 MEMCPY(s, tmp, char, l);
5508 break;
5509 case NEIGHBOR_NOT_CHAR:
5510 break;
5511 }
5512 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5513 /* wrapped to \0...\0. search next valid char. */
5514 enc_succ_char(s, l, enc);
5515 }
5516 if (!rb_enc_asciicompat(enc)) {
5517 MEMCPY(carry, s, char, l);
5518 carry_len = l;
5519 }
5520 carry_pos = s - sbeg;
5521 }
5523 }
5524 RESIZE_CAPA(str, slen + carry_len);
5525 sbeg = RSTRING_PTR(str);
5526 s = sbeg + carry_pos;
5527 memmove(s + carry_len, s, slen - carry_pos);
5528 memmove(s, carry, carry_len);
5529 slen += carry_len;
5530 STR_SET_LEN(str, slen);
5531 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5532 rb_enc_str_coderange(str);
5533 return str;
5534}
5535
5536
5537/*
5538 * call-seq:
5539 * succ! -> self
5540 *
5541 * Like String#succ, but modifies +self+ in place; returns +self+.
5542 *
5543 * Related: see {Modifying}[rdoc-ref:String@Modifying].
5544 */
5545
5546static VALUE
5547rb_str_succ_bang(VALUE str)
5548{
5549 rb_str_modify(str);
5550 str_succ(str);
5551 return str;
5552}
5553
5554static int
5555all_digits_p(const char *s, long len)
5556{
5557 while (len-- > 0) {
5558 if (!ISDIGIT(*s)) return 0;
5559 s++;
5560 }
5561 return 1;
5562}
5563
5564static int
5565str_upto_i(VALUE str, VALUE arg)
5566{
5567 rb_yield(str);
5568 return 0;
5569}
5570
5571/*
5572 * call-seq:
5573 * upto(other_string, exclusive = false) {|string| ... } -> self
5574 * upto(other_string, exclusive = false) -> new_enumerator
5575 *
5576 * :include: doc/string/upto.rdoc
5577 *
5578 */
5579
5580static VALUE
5581rb_str_upto(int argc, VALUE *argv, VALUE beg)
5582{
5583 VALUE end, exclusive;
5584
5585 rb_scan_args(argc, argv, "11", &end, &exclusive);
5586 RETURN_ENUMERATOR(beg, argc, argv);
5587 return rb_str_upto_each(beg, end, RTEST(exclusive), str_upto_i, Qnil);
5588}
5589
5590VALUE
5591rb_str_upto_each(VALUE beg, VALUE end, int excl, int (*each)(VALUE, VALUE), VALUE arg)
5592{
5593 VALUE current, after_end;
5594 ID succ;
5595 int n, ascii;
5596 rb_encoding *enc;
5597
5598 CONST_ID(succ, "succ");
5599 StringValue(end);
5600 enc = rb_enc_check(beg, end);
5601 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5602 /* single character */
5603 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5604 char c = RSTRING_PTR(beg)[0];
5605 char e = RSTRING_PTR(end)[0];
5606
5607 if (c > e || (excl && c == e)) return beg;
5608 for (;;) {
5609 VALUE str = rb_enc_str_new(&c, 1, enc);
5611 if ((*each)(str, arg)) break;
5612 if (!excl && c == e) break;
5613 c++;
5614 if (excl && c == e) break;
5615 }
5616 return beg;
5617 }
5618 /* both edges are all digits */
5619 if (ascii && ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
5620 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5621 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5622 VALUE b, e;
5623 int width;
5624
5625 width = RSTRING_LENINT(beg);
5626 b = rb_str_to_inum(beg, 10, FALSE);
5627 e = rb_str_to_inum(end, 10, FALSE);
5628 if (FIXNUM_P(b) && FIXNUM_P(e)) {
5629 long bi = FIX2LONG(b);
5630 long ei = FIX2LONG(e);
5631 rb_encoding *usascii = rb_usascii_encoding();
5632
5633 while (bi <= ei) {
5634 if (excl && bi == ei) break;
5635 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5636 bi++;
5637 }
5638 }
5639 else {
5640 ID op = excl ? '<' : idLE;
5641 VALUE args[2], fmt = rb_fstring_lit("%.*d");
5642
5643 args[0] = INT2FIX(width);
5644 while (rb_funcall(b, op, 1, e)) {
5645 args[1] = b;
5646 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5647 b = rb_funcallv(b, succ, 0, 0);
5648 }
5649 }
5650 return beg;
5651 }
5652 /* normal case */
5653 n = rb_str_cmp(beg, end);
5654 if (n > 0 || (excl && n == 0)) return beg;
5655
5656 after_end = rb_funcallv(end, succ, 0, 0);
5657 current = str_duplicate(rb_cString, beg);
5658 while (!rb_str_equal(current, after_end)) {
5659 VALUE next = Qnil;
5660 if (excl || !rb_str_equal(current, end))
5661 next = rb_funcallv(current, succ, 0, 0);
5662 if ((*each)(current, arg)) break;
5663 if (NIL_P(next)) break;
5664 current = next;
5665 StringValue(current);
5666 if (excl && rb_str_equal(current, end)) break;
5667 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5668 break;
5669 }
5670
5671 return beg;
5672}
5673
5674VALUE
5675rb_str_upto_endless_each(VALUE beg, int (*each)(VALUE, VALUE), VALUE arg)
5676{
5677 VALUE current;
5678 ID succ;
5679
5680 CONST_ID(succ, "succ");
5681 /* both edges are all digits */
5682 if (is_ascii_string(beg) && ISDIGIT(RSTRING_PTR(beg)[0]) &&
5683 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5684 VALUE b, args[2], fmt = rb_fstring_lit("%.*d");
5685 int width = RSTRING_LENINT(beg);
5686 b = rb_str_to_inum(beg, 10, FALSE);
5687 if (FIXNUM_P(b)) {
5688 long bi = FIX2LONG(b);
5689 rb_encoding *usascii = rb_usascii_encoding();
5690
5691 while (FIXABLE(bi)) {
5692 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5693 bi++;
5694 }
5695 b = LONG2NUM(bi);
5696 }
5697 args[0] = INT2FIX(width);
5698 while (1) {
5699 args[1] = b;
5700 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5701 b = rb_funcallv(b, succ, 0, 0);
5702 }
5703 }
5704 /* normal case */
5705 current = str_duplicate(rb_cString, beg);
5706 while (1) {
5707 VALUE next = rb_funcallv(current, succ, 0, 0);
5708 if ((*each)(current, arg)) break;
5709 current = next;
5710 StringValue(current);
5711 if (RSTRING_LEN(current) == 0)
5712 break;
5713 }
5714
5715 return beg;
5716}
5717
5718static int
5719include_range_i(VALUE str, VALUE arg)
5720{
5721 VALUE *argp = (VALUE *)arg;
5722 if (!rb_equal(str, *argp)) return 0;
5723 *argp = Qnil;
5724 return 1;
5725}
5726
5727VALUE
5728rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive)
5729{
5730 beg = rb_str_new_frozen(beg);
5731 StringValue(end);
5732 end = rb_str_new_frozen(end);
5733 if (NIL_P(val)) return Qfalse;
5734 val = rb_check_string_type(val);
5735 if (NIL_P(val)) return Qfalse;
5736 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5737 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5738 rb_enc_asciicompat(STR_ENC_GET(val))) {
5739 const char *bp = RSTRING_PTR(beg);
5740 const char *ep = RSTRING_PTR(end);
5741 const char *vp = RSTRING_PTR(val);
5742 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5743 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5744 return Qfalse;
5745 else {
5746 char b = *bp;
5747 char e = *ep;
5748 char v = *vp;
5749
5750 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
5751 if (b <= v && v < e) return Qtrue;
5752 return RBOOL(!RTEST(exclusive) && v == e);
5753 }
5754 }
5755 }
5756#if 0
5757 /* both edges are all digits */
5758 if (ISDIGIT(*bp) && ISDIGIT(*ep) &&
5759 all_digits_p(bp, RSTRING_LEN(beg)) &&
5760 all_digits_p(ep, RSTRING_LEN(end))) {
5761 /* TODO */
5762 }
5763#endif
5764 }
5765 rb_str_upto_each(beg, end, RTEST(exclusive), include_range_i, (VALUE)&val);
5766
5767 return RBOOL(NIL_P(val));
5768}
5769
5770static VALUE
5771rb_str_subpat(VALUE str, VALUE re, VALUE backref)
5772{
5773 if (rb_reg_search(re, str, 0, 0) >= 0) {
5774 VALUE match = rb_backref_get();
5775 int nth = rb_reg_backref_number(match, backref);
5776 return rb_reg_nth_match(nth, match);
5777 }
5778 return Qnil;
5779}
5780
5781static VALUE
5782rb_str_aref(VALUE str, VALUE indx)
5783{
5784 long idx;
5785
5786 if (FIXNUM_P(indx)) {
5787 idx = FIX2LONG(indx);
5788 }
5789 else if (RB_TYPE_P(indx, T_REGEXP)) {
5790 return rb_str_subpat(str, indx, INT2FIX(0));
5791 }
5792 else if (RB_TYPE_P(indx, T_STRING)) {
5793 if (rb_str_index(str, indx, 0) != -1)
5794 return str_duplicate(rb_cString, indx);
5795 return Qnil;
5796 }
5797 else {
5798 /* check if indx is Range */
5799 long beg, len = str_strlen(str, NULL);
5800 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
5801 case Qfalse:
5802 break;
5803 case Qnil:
5804 return Qnil;
5805 default:
5806 return rb_str_substr(str, beg, len);
5807 }
5808 idx = NUM2LONG(indx);
5809 }
5810
5811 return str_substr(str, idx, 1, FALSE);
5812}
5813
5814
5815/*
5816 * call-seq:
5817 * self[offset] -> new_string or nil
5818 * self[offset, size] -> new_string or nil
5819 * self[range] -> new_string or nil
5820 * self[regexp, capture = 0] -> new_string or nil
5821 * self[substring] -> new_string or nil
5822 *
5823 * :include: doc/string/aref.rdoc
5824 *
5825 */
5826
5827static VALUE
5828rb_str_aref_m(int argc, VALUE *argv, VALUE str)
5829{
5830 if (argc == 2) {
5831 if (RB_TYPE_P(argv[0], T_REGEXP)) {
5832 return rb_str_subpat(str, argv[0], argv[1]);
5833 }
5834 else {
5835 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5836 }
5837 }
5838 rb_check_arity(argc, 1, 2);
5839 return rb_str_aref(str, argv[0]);
5840}
5841
5842VALUE
5844{
5845 char *ptr = RSTRING_PTR(str);
5846 long olen = RSTRING_LEN(str), nlen;
5847
5848 str_modifiable(str);
5849 if (len > olen) len = olen;
5850 nlen = olen - len;
5851 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5852 char *oldptr = ptr;
5853 size_t old_capa = RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5854 int fl = (int)(RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5855 STR_SET_EMBED(str);
5856 ptr = RSTRING(str)->as.embed.ary;
5857 memmove(ptr, oldptr + len, nlen);
5858 if (fl == STR_NOEMBED) {
5859 SIZED_FREE_N(oldptr, old_capa);
5860 }
5861 }
5862 else {
5863 if (!STR_SHARED_P(str)) {
5864 VALUE shared = heap_str_make_shared(rb_obj_class(str), str);
5865 rb_enc_cr_str_exact_copy(shared, str);
5867 }
5868 ptr = RSTRING(str)->as.heap.ptr += len;
5869 }
5870 STR_SET_LEN(str, nlen);
5871
5872 if (!SHARABLE_MIDDLE_SUBSTRING) {
5873 TERM_FILL(ptr + nlen, TERM_LEN(str));
5874 }
5876 return str;
5877}
5878
5879static void
5880rb_str_update_1(VALUE str, long beg, long len, VALUE val, long vbeg, long vlen)
5881{
5882 char *sptr;
5883 long slen;
5884 int cr;
5885
5886 if (beg == 0 && vlen == 0) {
5887 rb_str_drop_bytes(str, len);
5888 return;
5889 }
5890
5891 str_modify_keep_cr(str);
5892 RSTRING_GETMEM(str, sptr, slen);
5893 if (len < vlen) {
5894 /* expand string */
5895 RESIZE_CAPA(str, slen + vlen - len);
5896 sptr = RSTRING_PTR(str);
5897 }
5898
5900 cr = rb_enc_str_coderange(val);
5901 else
5903
5904 if (vlen != len) {
5905 memmove(sptr + beg + vlen,
5906 sptr + beg + len,
5907 slen - (beg + len));
5908 }
5909 if (vlen < beg && len < 0) {
5910 MEMZERO(sptr + slen, char, -len);
5911 }
5912 if (vlen > 0) {
5913 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5914 }
5915 slen += vlen - len;
5916 STR_SET_LEN(str, slen);
5917 TERM_FILL(&sptr[slen], TERM_LEN(str));
5918 ENC_CODERANGE_SET(str, cr);
5919}
5920
5921static inline void
5922rb_str_update_0(VALUE str, long beg, long len, VALUE val)
5923{
5924 rb_str_update_1(str, beg, len, val, 0, RSTRING_LEN(val));
5925}
5926
5927void
5928rb_str_update(VALUE str, long beg, long len, VALUE val)
5929{
5930 long slen;
5931 char *p, *e;
5932 rb_encoding *enc;
5933 int singlebyte = single_byte_optimizable(str);
5934 int cr;
5935
5936 if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
5937
5938 StringValue(val);
5939 enc = rb_enc_check(str, val);
5940 slen = str_strlen(str, enc); /* rb_enc_check */
5941
5942 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5943 rb_raise(rb_eIndexError, "index %ld out of string", beg);
5944 }
5945 if (beg < 0) {
5946 beg += slen;
5947 }
5948 RUBY_ASSERT(beg >= 0);
5949 RUBY_ASSERT(beg <= slen);
5950
5951 if (len > slen - beg) {
5952 len = slen - beg;
5953 }
5954 p = str_nth(RSTRING_PTR(str), RSTRING_END(str), beg, enc, singlebyte);
5955 if (!p) p = RSTRING_END(str);
5956 e = str_nth(p, RSTRING_END(str), len, enc, singlebyte);
5957 if (!e) e = RSTRING_END(str);
5958 /* error check */
5959 beg = p - RSTRING_PTR(str); /* physical position */
5960 len = e - p; /* physical length */
5961 rb_str_update_0(str, beg, len, val);
5962 rb_enc_associate(str, enc);
5964 if (cr != ENC_CODERANGE_BROKEN)
5965 ENC_CODERANGE_SET(str, cr);
5966}
5967
5968static void
5969rb_str_subpat_set(VALUE str, VALUE re, VALUE backref, VALUE val)
5970{
5971 int nth;
5972 VALUE match;
5973 long start, end, len;
5974 rb_encoding *enc;
5975
5976 if (rb_reg_search(re, str, 0, 0) < 0) {
5977 rb_raise(rb_eIndexError, "regexp not matched");
5978 }
5979 match = rb_backref_get();
5980 nth = rb_reg_backref_number(match, backref);
5981 int num_regs = RMATCH_NREGS(match);
5982 if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
5983 rb_raise(rb_eIndexError, "index %d out of regexp", nth);
5984 }
5985 if (nth < 0) {
5986 nth += num_regs;
5987 }
5988
5989 start = RMATCH_BEG(match, nth);
5990 if (start == -1) {
5991 rb_raise(rb_eIndexError, "regexp group %d not matched", nth);
5992 }
5993 end = RMATCH_END(match, nth);
5994 len = end - start;
5995 StringValue(val);
5996 enc = rb_enc_check_str(str, val);
5997 rb_str_update_0(str, start, len, val);
5998 rb_enc_associate(str, enc);
5999}
6000
6001static VALUE
6002rb_str_aset(VALUE str, VALUE indx, VALUE val)
6003{
6004 long idx, beg;
6005
6006 switch (TYPE(indx)) {
6007 case T_REGEXP:
6008 rb_str_subpat_set(str, indx, INT2FIX(0), val);
6009 return val;
6010
6011 case T_STRING:
6012 beg = rb_str_index(str, indx, 0);
6013 if (beg < 0) {
6014 rb_raise(rb_eIndexError, "string not matched");
6015 }
6016 beg = rb_str_sublen(str, beg);
6017 rb_str_update(str, beg, str_strlen(indx, NULL), val);
6018 return val;
6019
6020 default:
6021 /* check if indx is Range */
6022 {
6023 long beg, len;
6024 if (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 2)) {
6025 rb_str_update(str, beg, len, val);
6026 return val;
6027 }
6028 }
6029 /* FALLTHROUGH */
6030
6031 case T_FIXNUM:
6032 idx = NUM2LONG(indx);
6033 rb_str_update(str, idx, 1, val);
6034 return val;
6035 }
6036}
6037
6038/*
6039 * call-seq:
6040 * self[index] = other_string -> new_string
6041 * self[start, length] = other_string -> new_string
6042 * self[range] = other_string -> new_string
6043 * self[regexp, capture = 0] = other_string -> new_string
6044 * self[substring] = other_string -> new_string
6045 *
6046 * :include: doc/string/aset.rdoc
6047 *
6048 */
6049
6050static VALUE
6051rb_str_aset_m(int argc, VALUE *argv, VALUE str)
6052{
6053 if (argc == 3) {
6054 if (RB_TYPE_P(argv[0], T_REGEXP)) {
6055 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6056 }
6057 else {
6058 rb_str_update(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
6059 }
6060 return argv[2];
6061 }
6062 rb_check_arity(argc, 2, 3);
6063 return rb_str_aset(str, argv[0], argv[1]);
6064}
6065
6066/*
6067 * call-seq:
6068 * insert(offset, other_string) -> self
6069 *
6070 * :include: doc/string/insert.rdoc
6071 *
6072 */
6073
6074static VALUE
6075rb_str_insert(VALUE str, VALUE idx, VALUE str2)
6076{
6077 long pos = NUM2LONG(idx);
6078
6079 if (pos == -1) {
6080 return rb_str_append(str, str2);
6081 }
6082 else if (pos < 0) {
6083 pos++;
6084 }
6085 rb_str_update(str, pos, 0, str2);
6086 return str;
6087}
6088
6089
6090/*
6091 * call-seq:
6092 * slice!(index) -> new_string or nil
6093 * slice!(start, length) -> new_string or nil
6094 * slice!(range) -> new_string or nil
6095 * slice!(regexp, capture = 0) -> new_string or nil
6096 * slice!(substring) -> new_string or nil
6097 *
6098 * Like String#[] (and its alias String#slice), except that:
6099 *
6100 * - Performs substitutions in +self+ (not in a copy of +self+).
6101 * - Returns the removed substring if any modifications were made, +nil+ otherwise.
6102 *
6103 * A few examples:
6104 *
6105 * s = 'hello'
6106 * s.slice!('e') # => "e"
6107 * s # => "hllo"
6108 * s.slice!('e') # => nil
6109 * s # => "hllo"
6110 *
6111 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6112 */
6113
6114static VALUE
6115rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
6116{
6117 VALUE result = Qnil;
6118 VALUE indx;
6119 long beg, len = 1;
6120 char *p;
6121
6122 rb_check_arity(argc, 1, 2);
6123 str_modify_keep_cr(str);
6124 indx = argv[0];
6125 if (RB_TYPE_P(indx, T_REGEXP)) {
6126 if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
6127 VALUE match = rb_backref_get();
6128 int num_regs = RMATCH_NREGS(match);
6129 int nth = 0;
6130 if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
6131 if ((nth += num_regs) <= 0) return Qnil;
6132 }
6133 else if (nth >= num_regs) return Qnil;
6134 beg = RMATCH_BEG(match, nth);
6135 len = RMATCH_END(match, nth) - beg;
6136 goto subseq;
6137 }
6138 else if (argc == 2) {
6139 beg = NUM2LONG(indx);
6140 len = NUM2LONG(argv[1]);
6141 goto num_index;
6142 }
6143 else if (FIXNUM_P(indx)) {
6144 beg = FIX2LONG(indx);
6145 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6146 if (!len) return Qnil;
6147 beg = p - RSTRING_PTR(str);
6148 goto subseq;
6149 }
6150 else if (RB_TYPE_P(indx, T_STRING)) {
6151 beg = rb_str_index(str, indx, 0);
6152 if (beg == -1) return Qnil;
6153 len = RSTRING_LEN(indx);
6154 result = str_duplicate(rb_cString, indx);
6155 goto squash;
6156 }
6157 else {
6158 switch (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 0)) {
6159 case Qnil:
6160 return Qnil;
6161 case Qfalse:
6162 beg = NUM2LONG(indx);
6163 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6164 if (!len) return Qnil;
6165 beg = p - RSTRING_PTR(str);
6166 goto subseq;
6167 default:
6168 goto num_index;
6169 }
6170 }
6171
6172 num_index:
6173 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6174 beg = p - RSTRING_PTR(str);
6175
6176 subseq:
6177 result = rb_str_new(RSTRING_PTR(str)+beg, len);
6178 rb_enc_cr_str_copy_for_substr(result, str);
6179
6180 squash:
6181 if (len > 0) {
6182 if (beg == 0) {
6183 rb_str_drop_bytes(str, len);
6184 }
6185 else {
6186 char *sptr = RSTRING_PTR(str);
6187 long slen = RSTRING_LEN(str);
6188 if (beg + len > slen) /* pathological check */
6189 len = slen - beg;
6190 memmove(sptr + beg,
6191 sptr + beg + len,
6192 slen - (beg + len));
6193 slen -= len;
6194 STR_SET_LEN(str, slen);
6195 TERM_FILL(&sptr[slen], TERM_LEN(str));
6196 }
6197 }
6198 return result;
6199}
6200
6201static VALUE
6202get_pat(VALUE pat)
6203{
6204 VALUE val;
6205
6206 switch (OBJ_BUILTIN_TYPE(pat)) {
6207 case T_REGEXP:
6208 return pat;
6209
6210 case T_STRING:
6211 break;
6212
6213 default:
6214 val = rb_check_string_type(pat);
6215 if (NIL_P(val)) {
6216 Check_Type(pat, T_REGEXP);
6217 }
6218 pat = val;
6219 }
6220
6221 return rb_reg_regcomp(pat);
6222}
6223
6224static VALUE
6225get_pat_quoted(VALUE pat, int check)
6226{
6227 VALUE val;
6228
6229 switch (OBJ_BUILTIN_TYPE(pat)) {
6230 case T_REGEXP:
6231 return pat;
6232
6233 case T_STRING:
6234 break;
6235
6236 default:
6237 val = rb_check_string_type(pat);
6238 if (NIL_P(val)) {
6239 Check_Type(pat, T_REGEXP);
6240 }
6241 pat = val;
6242 }
6243 if (check && is_broken_string(pat)) {
6244 rb_exc_raise(rb_reg_check_preprocess(pat));
6245 }
6246 return pat;
6247}
6248
6249static long
6250rb_pat_search0(VALUE pat, VALUE str, long pos, int set_backref_str, VALUE *match)
6251{
6252 if (BUILTIN_TYPE(pat) == T_STRING) {
6253 pos = rb_str_byteindex(str, pat, pos);
6254 if (set_backref_str) {
6255 if (pos >= 0) {
6256 str = rb_str_new_frozen_String(str);
6257 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6258 if (match) {
6259 *match = match_data;
6260 }
6261 }
6262 else {
6264 }
6265 }
6266 return pos;
6267 }
6268 else {
6269 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6270 }
6271}
6272
6273static long
6274rb_pat_search(VALUE pat, VALUE str, long pos, int set_backref_str)
6275{
6276 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6277}
6278
6279
6280/*
6281 * call-seq:
6282 * sub!(pattern, replacement) -> self or nil
6283 * sub!(pattern) {|match| ... } -> self or nil
6284 *
6285 * Like String#sub, except that:
6286 *
6287 * - Changes are made to +self+, not to copy of +self+.
6288 * - Returns +self+ if any changes are made, +nil+ otherwise.
6289 *
6290 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6291 */
6292
6293static VALUE
6294rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
6295{
6296 VALUE pat, repl, hash = Qnil;
6297 int iter = 0;
6298 long plen;
6299 int min_arity = rb_block_given_p() ? 1 : 2;
6300 long beg;
6301
6302 rb_check_arity(argc, min_arity, 2);
6303 if (argc == 1) {
6304 iter = 1;
6305 }
6306 else {
6307 repl = argv[1];
6308 if (!RB_TYPE_P(repl, T_STRING)) {
6309 hash = rb_check_hash_type(repl);
6310 if (NIL_P(hash)) {
6311 StringValue(repl);
6312 }
6313 }
6314 }
6315
6316 pat = get_pat_quoted(argv[0], 1);
6317
6318 str_modifiable(str);
6319 beg = rb_pat_search(pat, str, 0, 1);
6320 if (beg >= 0) {
6321 rb_encoding *enc;
6322 int cr = ENC_CODERANGE(str);
6323 long beg0, end0;
6324 VALUE match, match0 = Qnil;
6325 char *p, *rp;
6326 long len, rlen;
6327
6328 match = rb_backref_get();
6329 if (RB_TYPE_P(pat, T_STRING)) {
6330 beg0 = beg;
6331 end0 = beg0 + RSTRING_LEN(pat);
6332 match0 = pat;
6333 }
6334 else {
6335 beg0 = RMATCH_BEG(match, 0);
6336 end0 = RMATCH_END(match, 0);
6337 if (iter) match0 = rb_reg_nth_match(0, match);
6338 }
6339
6340 if (iter || !NIL_P(hash)) {
6341 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6342
6343 if (iter) {
6344 repl = rb_obj_as_string(rb_yield(match0));
6345 }
6346 else {
6347 repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0));
6348 repl = rb_obj_as_string(repl);
6349 }
6350 str_mod_check(str, p, len);
6351 rb_check_frozen(str);
6352 }
6353 else {
6354 repl = rb_reg_regsub_match(repl, str, match);
6355 }
6356
6357 enc = rb_enc_compatible(str, repl);
6358 if (!enc) {
6359 rb_encoding *str_enc = STR_ENC_GET(str);
6360 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6361 if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
6362 coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
6363 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
6364 rb_enc_inspect_name(str_enc),
6365 rb_enc_inspect_name(STR_ENC_GET(repl)));
6366 }
6367 enc = STR_ENC_GET(repl);
6368 }
6369 rb_str_modify(str);
6370 rb_enc_associate(str, enc);
6372 int cr2 = ENC_CODERANGE(repl);
6373 if (cr2 == ENC_CODERANGE_BROKEN ||
6374 (cr == ENC_CODERANGE_VALID && cr2 == ENC_CODERANGE_7BIT))
6376 else
6377 cr = cr2;
6378 }
6379 plen = end0 - beg0;
6380 rlen = RSTRING_LEN(repl);
6381 len = RSTRING_LEN(str);
6382 if (rlen > plen) {
6383 RESIZE_CAPA(str, len + rlen - plen);
6384 }
6385 p = RSTRING_PTR(str);
6386 if (rlen != plen) {
6387 memmove(p + beg0 + rlen, p + beg0 + plen, len - beg0 - plen);
6388 }
6389 rp = RSTRING_PTR(repl);
6390 memmove(p + beg0, rp, rlen);
6391 len += rlen - plen;
6392 STR_SET_LEN(str, len);
6393 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
6394 ENC_CODERANGE_SET(str, cr);
6395
6396 RB_GC_GUARD(match);
6397
6398 return str;
6399 }
6400 return Qnil;
6401}
6402
6403
6404/*
6405 * call-seq:
6406 * sub(pattern, replacement) -> new_string
6407 * sub(pattern) {|match| ... } -> new_string
6408 *
6409 * :include: doc/string/sub.rdoc
6410 */
6411
6412static VALUE
6413rb_str_sub(int argc, VALUE *argv, VALUE str)
6414{
6415 str = str_duplicate(rb_cString, str);
6416 rb_str_sub_bang(argc, argv, str);
6417 return str;
6418}
6419
6420static VALUE
6421str_gsub(int argc, VALUE *argv, VALUE str, int bang)
6422{
6423 VALUE pat, val = Qnil, repl, match0 = Qnil, dest, hash = Qnil, match = Qnil;
6424 long beg, beg0, end0;
6425 long offset, blen, slen, len, last;
6426 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6427 char *sp, *cp;
6428 int need_backref_str = -1;
6429 rb_encoding *str_enc;
6430
6431 switch (argc) {
6432 case 1:
6433 RETURN_ENUMERATOR(str, argc, argv);
6434 mode = ITER;
6435 break;
6436 case 2:
6437 repl = argv[1];
6438 if (!RB_TYPE_P(repl, T_STRING)) {
6439 hash = rb_check_hash_type(repl);
6440 if (NIL_P(hash)) {
6441 StringValue(repl);
6442 }
6443 else if (rb_hash_default_unredefined(hash) && !FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6444 mode = FAST_MAP;
6445 }
6446 else {
6447 mode = MAP;
6448 }
6449 }
6450 break;
6451 default:
6452 rb_error_arity(argc, 1, 2);
6453 }
6454
6455 pat = get_pat_quoted(argv[0], 1);
6456 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6457
6458 if (beg < 0) {
6459 if (bang) return Qnil; /* no match, no substitution */
6460 return str_duplicate(rb_cString, str);
6461 }
6462 if (bang) str_modify_keep_cr(str);
6463
6464 offset = 0;
6465 blen = RSTRING_LEN(str) + 30; /* len + margin */
6466 dest = rb_str_buf_new(blen);
6467 sp = RSTRING_PTR(str);
6468 slen = RSTRING_LEN(str);
6469 cp = sp;
6470 str_enc = STR_ENC_GET(str);
6471 rb_enc_associate(dest, str_enc);
6472 ENC_CODERANGE_SET(dest, rb_enc_asciicompat(str_enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
6473
6474 do {
6475 if (RB_TYPE_P(pat, T_STRING)) {
6476 beg0 = beg;
6477 end0 = beg0 + RSTRING_LEN(pat);
6478 match0 = pat;
6479 }
6480 else {
6481 beg0 = RMATCH_BEG(match, 0);
6482 end0 = RMATCH_END(match, 0);
6483 if (mode == ITER) match0 = rb_reg_nth_match(0, match);
6484 }
6485
6486 if (mode != STR) {
6487 if (mode == ITER) {
6488 val = rb_obj_as_string(rb_yield(match0));
6489 }
6490 else {
6491 struct RString fake_str = {RBASIC_INIT};
6492 VALUE key;
6493 if (mode == FAST_MAP) {
6494 // It is safe to use a fake_str here because we established that it won't escape,
6495 // as it's only used for `rb_hash_aref` and we checked the hash doesn't have a
6496 // default proc.
6497 key = setup_fake_str(&fake_str, sp + beg0, end0 - beg0, ENCODING_GET_INLINED(str));
6498 }
6499 else {
6500 key = rb_str_subseq(str, beg0, end0 - beg0);
6501 }
6502 val = rb_hash_aref(hash, key);
6503 val = rb_obj_as_string(val);
6504 }
6505 str_mod_check(str, sp, slen);
6506 if (val == dest) { /* paranoid check [ruby-dev:24827] */
6507 rb_raise(rb_eRuntimeError, "block should not cheat");
6508 }
6509 }
6510 else if (need_backref_str) {
6511 val = rb_reg_regsub_match(repl, str, match);
6512 if (need_backref_str < 0) {
6513 need_backref_str = val != repl;
6514 }
6515 }
6516 else {
6517 val = repl;
6518 }
6519
6520 len = beg0 - offset; /* copy pre-match substr */
6521 if (len) {
6522 rb_enc_str_buf_cat(dest, cp, len, str_enc);
6523 }
6524
6525 rb_str_buf_append(dest, val);
6526
6527 last = offset;
6528 offset = end0;
6529 if (beg0 == end0) {
6530 /*
6531 * Always consume at least one character of the input string
6532 * in order to prevent infinite loops.
6533 */
6534 if (RSTRING_LEN(str) <= end0) break;
6535 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0, RSTRING_END(str), str_enc);
6536 rb_enc_str_buf_cat(dest, RSTRING_PTR(str)+end0, len, str_enc);
6537 offset = end0 + len;
6538 }
6539 cp = RSTRING_PTR(str) + offset;
6540 if (offset > RSTRING_LEN(str)) break;
6541
6542 // In FAST_MAP and STR mode the backref can't escape so we can re-use the MatchData safely.
6543 if (mode != FAST_MAP && mode != STR) {
6544 match = Qnil;
6545 }
6546 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6547
6548 RB_GC_GUARD(match);
6549 } while (beg >= 0);
6550
6551 if (RSTRING_LEN(str) > offset) {
6552 rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
6553 }
6554 rb_pat_search0(pat, str, last, 1, &match);
6555 if (bang) {
6556 str_shared_replace(str, dest);
6557 }
6558 else {
6559 str = dest;
6560 }
6561
6562 return str;
6563}
6564
6565
6566/*
6567 * call-seq:
6568 * gsub!(pattern, replacement) -> self or nil
6569 * gsub!(pattern) {|match| ... } -> self or nil
6570 * gsub!(pattern) -> an_enumerator
6571 *
6572 * Like String#gsub, except that:
6573 *
6574 * - Performs substitutions in +self+ (not in a copy of +self+).
6575 * - Returns +self+ if any substitutions were performed, +nil+ otherwise.
6576 *
6577 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6578 */
6579
6580static VALUE
6581rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
6582{
6583 str_modifiable(str);
6584 return str_gsub(argc, argv, str, 1);
6585}
6586
6587
6588/*
6589 * call-seq:
6590 * gsub(pattern, replacement) -> new_string
6591 * gsub(pattern) {|match| ... } -> new_string
6592 * gsub(pattern) -> enumerator
6593 *
6594 * Returns a copy of +self+ with zero or more substrings replaced.
6595 *
6596 * Argument +pattern+ may be a string or a Regexp;
6597 * argument +replacement+ may be a string or a Hash.
6598 * Varying types for the argument values makes this method very versatile.
6599 *
6600 * Below are some simple examples;
6601 * for many more examples, see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
6602 *
6603 * With arguments +pattern+ and string +replacement+ given,
6604 * replaces each matching substring with the given +replacement+ string:
6605 *
6606 * s = 'abracadabra'
6607 * s.gsub('ab', 'AB') # => "ABracadABra"
6608 * s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
6609 *
6610 * With arguments +pattern+ and hash +replacement+ given,
6611 * replaces each matching substring with a value from the given +replacement+ hash,
6612 * or removes it:
6613 *
6614 * h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
6615 * s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
6616 * s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
6617 *
6618 * With argument +pattern+ and a block given,
6619 * calls the block with each matching substring;
6620 * replaces that substring with the block's return value:
6621 *
6622 * s.gsub(/[a-d]/) {|substring| substring.upcase }
6623 * # => "ABrACADABrA"
6624 *
6625 * With argument +pattern+ and no block given,
6626 * returns a new Enumerator.
6627 *
6628 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
6629 */
6630
6631static VALUE
6632rb_str_gsub(int argc, VALUE *argv, VALUE str)
6633{
6634 return str_gsub(argc, argv, str, 0);
6635}
6636
6637
6638/*
6639 * call-seq:
6640 * replace(other_string) -> self
6641 *
6642 * Replaces the contents of +self+ with the contents of +other_string+;
6643 * returns +self+:
6644 *
6645 * s = 'foo' # => "foo"
6646 * s.replace('bar') # => "bar"
6647 *
6648 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6649 */
6650
6651VALUE
6653{
6654 str_modifiable(str);
6655 if (str == str2) return str;
6656
6657 StringValue(str2);
6658 str_discard(str);
6659 return str_replace(str, str2);
6660}
6661
6662/*
6663 * call-seq:
6664 * clear -> self
6665 *
6666 * Removes the contents of +self+:
6667 *
6668 * s = 'foo'
6669 * s.clear # => ""
6670 * s # => ""
6671 *
6672 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6673 */
6674
6675static VALUE
6676rb_str_clear(VALUE str)
6677{
6678 str_discard(str);
6679 STR_SET_EMBED(str);
6680 STR_SET_LEN(str, 0);
6681 RSTRING_PTR(str)[0] = 0;
6682 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6684 else
6686 return str;
6687}
6688
6689/*
6690 * call-seq:
6691 * chr -> string
6692 *
6693 * :include: doc/string/chr.rdoc
6694 *
6695 */
6696
6697static VALUE
6698rb_str_chr(VALUE str)
6699{
6700 return rb_str_substr(str, 0, 1);
6701}
6702
6703/*
6704 * call-seq:
6705 * getbyte(index) -> integer or nil
6706 *
6707 * :include: doc/string/getbyte.rdoc
6708 *
6709 */
6710VALUE
6711rb_str_getbyte(VALUE str, VALUE index)
6712{
6713 long pos = NUM2LONG(index);
6714
6715 if (pos < 0)
6716 pos += RSTRING_LEN(str);
6717 if (pos < 0 || RSTRING_LEN(str) <= pos)
6718 return Qnil;
6719
6720 return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
6721}
6722
6723/*
6724 * call-seq:
6725 * setbyte(index, integer) -> integer
6726 *
6727 * Sets the byte at zero-based offset +index+ to the value of the given +integer+;
6728 * returns +integer+:
6729 *
6730 * s = 'xyzzy'
6731 * s.setbyte(2, 129) # => 129
6732 * s # => "xy\x81zy"
6733 *
6734 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6735 */
6736VALUE
6737rb_str_setbyte(VALUE str, VALUE index, VALUE value)
6738{
6739 long pos = NUM2LONG(index);
6740 long len = RSTRING_LEN(str);
6741 char *ptr, *head, *left = 0;
6742 rb_encoding *enc;
6743 int cr = ENC_CODERANGE_UNKNOWN, width, nlen;
6744
6745 if (pos < -len || len <= pos)
6746 rb_raise(rb_eIndexError, "index %ld out of string", pos);
6747 if (pos < 0)
6748 pos += len;
6749
6750 VALUE v = rb_to_int(value);
6751 VALUE w = rb_int_and(v, INT2FIX(0xff));
6752 char byte = (char)(NUM2INT(w) & 0xFF);
6753
6754 if (!str_independent(str))
6755 str_make_independent(str);
6756 enc = STR_ENC_GET(str);
6757 head = RSTRING_PTR(str);
6758 ptr = &head[pos];
6759 if (!STR_EMBED_P(str)) {
6760 cr = ENC_CODERANGE(str);
6761 switch (cr) {
6762 case ENC_CODERANGE_7BIT:
6763 left = ptr;
6764 *ptr = byte;
6765 if (ISASCII(byte)) goto end;
6766 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6767 if (!MBCLEN_CHARFOUND_P(nlen))
6769 else
6771 goto end;
6773 left = rb_enc_left_char_head(head, ptr, head+len, enc);
6774 width = rb_enc_precise_mbclen(left, head+len, enc);
6775 *ptr = byte;
6776 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6777 if (!MBCLEN_CHARFOUND_P(nlen))
6779 else if (MBCLEN_CHARFOUND_LEN(nlen) != width || ISASCII(byte))
6781 goto end;
6782 }
6783 }
6785 *ptr = byte;
6786
6787 end:
6788 return value;
6789}
6790
6791static inline bool
6792str_bit_offset_out_of_range(long byte_len, uint64_t bit_offset)
6793{
6794 /* Compare byte indexes to avoid overflowing byte_len * CHAR_BIT. */
6795 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6796}
6797
6798/*
6799 * Keep both the full bit offset and its long representation. Most calls use a
6800 * Fixnum-sized offset and can stay on the original long fast path; only large
6801 * Bignum offsets need the uint64_t path below. This matters on platforms
6802 * where long is narrower than the address space, such as 32-bit and LLP64.
6803 */
6805 uint64_t value;
6806 long long_value;
6807 bool fits_long;
6808};
6809
6810static inline struct str_bit_offset
6811str_bit_offset_from_index(VALUE index)
6812{
6813 VALUE integer = rb_to_int(index);
6814 struct str_bit_offset offset;
6815
6816 /*
6817 * FIXNUM_P only decides whether the common long path is immediately usable.
6818 * This covers practically all offsets on LP64 platforms; Bignum offsets
6819 * are still accepted below when they fit in uint64_t, mainly for platforms
6820 * with 32-bit long where large strings can have Bignum bit offsets.
6821 */
6822 if (FIXNUM_P(integer)) {
6823 offset.long_value = FIX2LONG(integer);
6824 if (offset.long_value < 0) {
6825 rb_raise(rb_eIndexError, "bit index out of range");
6826 }
6827 offset.value = (uint64_t)offset.long_value;
6828 offset.fits_long = true;
6829 return offset;
6830 }
6831
6832 RUBY_ASSERT(RB_TYPE_P(integer, T_BIGNUM));
6833 if (rb_int_negative_p(integer)) {
6834 rb_raise(rb_eIndexError, "bit index out of range");
6835 }
6836 if (rb_cmpint(rb_int_cmp(integer, ULL2NUM(UINT64_MAX)), integer, ULL2NUM(UINT64_MAX)) > 0) {
6837 rb_raise(rb_eArgError, "bit index out of representable range");
6838 }
6839
6840 offset.value = (uint64_t)NUM2ULL(integer);
6841 if (offset.value <= (uint64_t)LONG_MAX) {
6842 offset.long_value = (long)offset.value;
6843 offset.fits_long = true;
6844 }
6845 else {
6846 offset.long_value = 0;
6847 offset.fits_long = false;
6848 }
6849 return offset;
6850}
6851
6852/*
6853 * Bit lengths share the offset's representable range.
6854 * A negative length is an ArgumentError rather than an IndexError.
6855 */
6856static uint64_t
6857str_bit_length_from_index(VALUE index)
6858{
6859 VALUE integer = rb_to_int(index);
6860
6861 if (FIXNUM_P(integer)) {
6862 long value = FIX2LONG(integer);
6863 if (value < 0) {
6864 rb_raise(rb_eArgError, "negative bit length");
6865 }
6866 return (uint64_t)value;
6867 }
6868
6869 RUBY_ASSERT(RB_TYPE_P(integer, T_BIGNUM));
6870 if (rb_int_negative_p(integer)) {
6871 rb_raise(rb_eArgError, "negative bit length");
6872 }
6873 if (rb_cmpint(rb_int_cmp(integer, ULL2NUM(UINT64_MAX)), integer, ULL2NUM(UINT64_MAX)) > 0) {
6874 rb_raise(rb_eArgError, "bit length out of representable range");
6875 }
6876 return (uint64_t)NUM2ULL(integer);
6877}
6878
6879static inline uint64_t
6880str_bit_size(long byte_len)
6881{
6882 /*
6883 * byte_len * CHAR_BIT overflows uint64_t only for byte_len >= 2**61 which cannot
6884 * be allocated. Saturate so that unreachable cases cannot wrap.
6885 */
6886 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT) return UINT64_MAX;
6887 return (uint64_t)byte_len * CHAR_BIT;
6888}
6889
6891 uint64_t beg;
6892 uint64_t end_exclusive; /* meaningful only when end_open is false */
6893 bool end_open; /* a nil end: the region runs to the end of self */
6894};
6895
6896/*
6897 * Coerce a bit Range's endpoints to bit offsets. This may run arbitrary Ruby
6898 * (Integer#to_int on the endpoints), so it does NOT read the string's length:
6899 * The caller must resolve the length only after this returns, otherwise
6900 * to_int that reallocates self would leave a stale size.
6901 */
6902static void
6903str_bit_range_to_offsets(VALUE range, struct str_bit_range *out)
6904{
6905 VALUE beg_v, end_v;
6906 int excl;
6907
6908 /*
6909 * We don't use rb_range_beg_len: it counts negative endpoints from the end,
6910 * which is an IndexError for bit positions, and it is limited to long instead
6911 * of uint64_t.
6912 */
6913 rb_range_values(range, &beg_v, &end_v, &excl);
6914
6915 out->beg = NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6916 if (NIL_P(end_v)) {
6917 out->end_open = true;
6918 out->end_exclusive = 0;
6919 }
6920 else {
6921 uint64_t end = str_bit_offset_from_index(end_v).value;
6922 out->end_open = false;
6923 /*
6924 * The saturation loses one position only for an inclusive end of
6925 * 2**64-1, which lies beyond any real string either way.
6926 */
6927 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6928 }
6929}
6930
6931/*
6932 * Turn a coerced Range into (beg, len) against the now-current total bit size.
6933 * The length is deliberately not clamped to the bits available, so a reading
6934 * caller can clamp while a writing caller detects the overrun and raises.
6935 */
6936static bool
6937str_bit_range_resolve(const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6938{
6939 uint64_t beg = range->beg;
6940 if (beg > total_bits) return false;
6941
6942 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6943 if (end_exclusive < beg) end_exclusive = beg;
6944
6945 *begp = beg;
6946 *lenp = end_exclusive - beg;
6947 return true;
6948}
6949
6950static bool
6951str_lsb_first_from_opts(VALUE opts)
6952{
6953 static ID keywords[1];
6954 VALUE vlsb_first;
6955
6956 if (!keywords[0]) {
6957 keywords[0] = rb_intern_const("lsb_first");
6958 }
6959
6960 rb_get_kwargs(opts, keywords, 0, 1, &vlsb_first);
6961 if (vlsb_first == Qundef || vlsb_first == Qtrue) {
6962 return true;
6963 }
6964 if (vlsb_first == Qfalse) {
6965 return false;
6966 }
6967 rb_raise(rb_eArgError, "lsb_first must be true or false");
6968 UNREACHABLE_RETURN(false);
6969}
6970
6971static bool
6972str_lsb_first(int argc, VALUE *argv, VALUE *index)
6973{
6974 VALUE opts;
6975
6976 rb_scan_args(argc, argv, "1:", index, &opts);
6977 return str_lsb_first_from_opts(opts);
6978}
6979
6980static inline uint64_t
6981str_logical_to_physical_bit64(uint64_t logical, bool lsb_first)
6982{
6983 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
6984}
6985
6986static inline long
6987str_logical_to_physical_bit(long logical, bool lsb_first)
6988{
6989 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
6990}
6991
6993 long byte_index;
6994 unsigned int bit_offset;
6995};
6996
6997static inline struct str_bit_location
6998str_bit_location_from_offset(uint64_t logical, bool lsb_first)
6999{
7000 /*
7001 * When long is 32-bit, a bit offset for a large string can be a Bignum
7002 * while the byte index still fits in long, which is RSTRING_LEN's type.
7003 */
7004 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7005 struct str_bit_location location;
7006 location.byte_index = (long)(physical / CHAR_BIT);
7007 location.bit_offset = (unsigned int)(physical % CHAR_BIT);
7008 return location;
7009}
7010
7011static inline int
7012str_get_bit(const char *ptr, long bit_index)
7013{
7014 return (((unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7015}
7016
7017static inline int
7018str_get_bit_location(const char *ptr, struct str_bit_location location)
7019{
7020 return (((unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7021}
7022
7023static int
7024str_bit_get(int argc, VALUE *argv, VALUE str)
7025{
7026 VALUE index;
7027 bool lsb_first = str_lsb_first(argc, argv, &index);
7028 struct str_bit_offset offset = str_bit_offset_from_index(index);
7029
7030 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7031 return -1;
7032 }
7033
7034 if (offset.fits_long) {
7035 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.long_value, lsb_first));
7036 }
7037 else {
7038 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7039 }
7040}
7041
7042/*
7043 * call-seq:
7044 * bit_get(offset, lsb_first: true) -> 0, 1, or nil
7045 *
7046 * :include: doc/string/bit_get.rdoc
7047 *
7048 */
7049static VALUE
7050rb_str_bit_get(int argc, VALUE *argv, VALUE str)
7051{
7052 int bit = str_bit_get(argc, argv, str);
7053 return bit < 0 ? Qnil : INT2FIX(bit);
7054}
7055
7056/*
7057 * call-seq:
7058 * bit_set?(offset, lsb_first: true) -> true, false, or nil
7059 *
7060 * :include: doc/string/bit_set_p.rdoc
7061 *
7062 */
7063static VALUE
7064rb_str_bit_set_p(int argc, VALUE *argv, VALUE str)
7065{
7066 int bit = str_bit_get(argc, argv, str);
7067 return bit < 0 ? Qnil : RBOOL(bit);
7068}
7069
7070enum str_bit_mutation {
7071 STR_BIT_SET,
7072 STR_BIT_CLEAR,
7073 STR_BIT_FLIP
7074};
7075
7076/*
7077 * Mask for the logical in-byte positions lo..hi (0 <= lo <= hi <= 7) of one
7078 * byte. A contiguous logical run stays contiguous within a byte under both
7079 * numbering conventions; MSB-first only mirrors it.
7080 */
7081static inline unsigned char
7082str_bit_region_byte_mask(unsigned int lo, unsigned int hi, bool lsb_first)
7083{
7084 if (lsb_first) {
7085 return (unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7086 }
7087 else {
7088 return (unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7089 }
7090}
7091
7092static inline void
7093str_apply_bit_mask(unsigned char *byte, unsigned char mask, enum str_bit_mutation mutation)
7094{
7095 switch (mutation) {
7096 case STR_BIT_SET:
7097 *byte |= mask;
7098 break;
7099 case STR_BIT_CLEAR:
7100 *byte &= (unsigned char)~mask;
7101 break;
7102 case STR_BIT_FLIP:
7103 *byte ^= mask;
7104 break;
7105 }
7106}
7107
7108/* The caller has bounds-checked [beg, beg+len) and called rb_str_modify. */
7109static void
7110str_mutate_bit_region(unsigned char *ptr, uint64_t beg, uint64_t len, bool lsb_first, enum str_bit_mutation mutation)
7111{
7112 uint64_t first_bit = beg;
7113 uint64_t last_bit = beg + len - 1;
7114 long first_byte = (long)(first_bit / CHAR_BIT);
7115 long last_byte = (long)(last_bit / CHAR_BIT);
7116 unsigned int first_off = (unsigned int)(first_bit % CHAR_BIT);
7117 unsigned int last_off = (unsigned int)(last_bit % CHAR_BIT);
7118
7119 if (first_byte == last_byte) {
7120 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7121 return;
7122 }
7123
7124 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7125 long middle_len = last_byte - first_byte - 1;
7126 if (middle_len > 0) {
7127 unsigned char *middle = ptr + first_byte + 1;
7128 switch (mutation) {
7129 case STR_BIT_SET:
7130 memset(middle, 0xFF, middle_len);
7131 break;
7132 case STR_BIT_CLEAR:
7133 memset(middle, 0, middle_len);
7134 break;
7135 case STR_BIT_FLIP:
7136 /*
7137 * Byte loop on purpose: the compiler auto-vectorizes it (verified on gcc 13.3
7138 * and clang 18.1 with x86_64), and being read-modify-write, the flip is memory-bound,
7139 * so a manual word-at-a-time XOR loop was measured to be no faster.
7140 */
7141 for (long i = 0; i < middle_len; i++) {
7142 middle[i] ^= 0xFF;
7143 }
7144 break;
7145 }
7146 }
7147 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7148}
7149
7150static VALUE
7151str_mutate_single_bit(VALUE str, VALUE index, bool lsb_first, enum str_bit_mutation mutation)
7152{
7153 struct str_bit_offset offset = str_bit_offset_from_index(index);
7154 struct str_bit_location location;
7155 long bit_index;
7156 unsigned char *ptr;
7157 unsigned char mask;
7158
7159 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7160 rb_raise(rb_eIndexError, "bit index out of range");
7161 }
7162
7163 rb_str_modify(str);
7164 ptr = (unsigned char *)RSTRING_PTR(str);
7165 if (offset.fits_long) {
7166 bit_index = str_logical_to_physical_bit(offset.long_value, lsb_first);
7167 mask = (unsigned char)(1u << (bit_index % CHAR_BIT));
7168 location.byte_index = bit_index / CHAR_BIT;
7169 }
7170 else {
7171 location = str_bit_location_from_offset(offset.value, lsb_first);
7172 mask = (unsigned char)(1u << location.bit_offset);
7173 }
7174
7175 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7176 return str;
7177}
7178
7179static VALUE
7180str_mutate_bit(int argc, VALUE *argv, VALUE str, enum str_bit_mutation mutation)
7181{
7182 VALUE target, length_v, opts;
7183 uint64_t beg = 0, len = 0;
7184
7185 /* Count positional arguments so that an explicit nil is not mistaken for an omitted one. */
7186 int nargs = rb_scan_args(argc, argv, "11:", &target, &length_v, &opts);
7187 bool lsb_first = str_lsb_first_from_opts(opts);
7188
7189 bool is_range = rb_obj_is_kind_of(target, rb_cRange);
7190 if (nargs == 1 && !is_range) {
7191 return str_mutate_single_bit(str, target, lsb_first, mutation);
7192 }
7193
7194 struct str_bit_range range = {0};
7195 struct str_bit_offset offset;
7196 if (is_range) {
7197 if (nargs == 2) {
7198 rb_raise(rb_eArgError, "bit length not allowed with a Range");
7199 }
7200 str_bit_range_to_offsets(target, &range);
7201 }
7202 else {
7203 offset = str_bit_offset_from_index(target);
7204 len = str_bit_length_from_index(length_v);
7205 }
7206
7207 /*
7208 * A region that begins past the end is out of range even when it is
7209 * empty, and one that runs past the end is not allowed to silently
7210 * shrink: both are errors for a mutation, unlike the clamping reads.
7211 * An empty region whose start is within 0..bitsize writes nothing.
7212 */
7213 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7214 if (is_range) {
7215 if (!str_bit_range_resolve(&range, total_bits, &beg, &len) || len > total_bits - beg) {
7216 rb_raise(rb_eIndexError, "bit range out of range");
7217 }
7218 }
7219 else {
7220 beg = offset.value;
7221 if (beg > total_bits || len > total_bits - beg) {
7222 rb_raise(rb_eIndexError, "bit range out of range");
7223 }
7224 }
7225 /* Even a zero-length write requires a mutable receiver. */
7226 rb_check_frozen(str);
7227 if (len == 0) return str;
7228
7229 rb_str_modify(str);
7230 str_mutate_bit_region((unsigned char *)RSTRING_PTR(str), beg, len, lsb_first, mutation);
7231 return str;
7232}
7233
7234/*
7235 * call-seq:
7236 * bit_set(offset, lsb_first: true) -> self
7237 * bit_set(offset, length, lsb_first: true) -> self
7238 * bit_set(range, lsb_first: true) -> self
7239 *
7240 * :include: doc/string/bit_set.rdoc
7241 *
7242 */
7243static VALUE
7244rb_str_bit_set(int argc, VALUE *argv, VALUE str)
7245{
7246 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7247}
7248
7249/*
7250 * call-seq:
7251 * bit_clear(offset, lsb_first: true) -> self
7252 * bit_clear(offset, length, lsb_first: true) -> self
7253 * bit_clear(range, lsb_first: true) -> self
7254 *
7255 * :include: doc/string/bit_clear.rdoc
7256 *
7257 */
7258static VALUE
7259rb_str_bit_clear(int argc, VALUE *argv, VALUE str)
7260{
7261 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7262}
7263
7264/*
7265 * call-seq:
7266 * bit_flip(offset, lsb_first: true) -> self
7267 * bit_flip(offset, length, lsb_first: true) -> self
7268 * bit_flip(range, lsb_first: true) -> self
7269 *
7270 * :include: doc/string/bit_flip.rdoc
7271 *
7272 */
7273static VALUE
7274rb_str_bit_flip(int argc, VALUE *argv, VALUE str)
7275{
7276 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7277}
7278
7279static uint64_t
7280str_count_bits(const unsigned char *ptr, long len)
7281{
7282 uint64_t count = 0;
7283 long off = 0;
7284 long unrolled_end = len & ~31L;
7285 long aligned_end = len & ~7L;
7286
7287 // 32 bytes (256 bits) at a time
7288 for (; off < unrolled_end; off += 32) {
7289 uint64_t w0, w1, w2, w3;
7290 memcpy(&w0, ptr + off, 8);
7291 memcpy(&w1, ptr + off + 8, 8);
7292 memcpy(&w2, ptr + off + 16, 8);
7293 memcpy(&w3, ptr + off + 24, 8);
7294 count += rb_popcount64(w0);
7295 count += rb_popcount64(w1);
7296 count += rb_popcount64(w2);
7297 count += rb_popcount64(w3);
7298 }
7299
7300 // 8 bytes (64 bits) at a time
7301 for (; off < aligned_end; off += 8) {
7302 uint64_t word;
7303 memcpy(&word, ptr + off, 8);
7304 count += rb_popcount64(word);
7305 }
7306
7307 // remaining bytes
7308 if (off < len) {
7309 uint64_t word = 0;
7310 int shift = 0;
7311 for (; off < len; off++, shift += CHAR_BIT) {
7312 word |= (uint64_t)ptr[off] << shift;
7313 }
7314 count += rb_popcount64(word);
7315 }
7316
7317 return count;
7318}
7319
7320static uint64_t
7321str_count_bits_region(const unsigned char *ptr, uint64_t beg, uint64_t len, bool lsb_first)
7322{
7323 uint64_t first_bit = beg;
7324 uint64_t last_bit = beg + len - 1;
7325 long first_byte = (long)(first_bit / CHAR_BIT);
7326 long last_byte = (long)(last_bit / CHAR_BIT);
7327 unsigned int first_off = (unsigned int)(first_bit % CHAR_BIT);
7328 unsigned int last_off = (unsigned int)(last_bit % CHAR_BIT);
7329
7330 if (first_byte == last_byte) {
7331 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7332 }
7333
7334 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7335 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7336 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7337 return count;
7338}
7339
7340/*
7341 * call-seq:
7342 * bit_count -> integer
7343 * bit_count(offset, length, lsb_first: true) -> integer
7344 * bit_count(range, lsb_first: true) -> integer
7345 *
7346 * :include: doc/string/bit_count.rdoc
7347 *
7348 */
7349static VALUE
7350rb_str_bit_count(int argc, VALUE *argv, VALUE str)
7351{
7352 VALUE v0, v1, opts;
7353 uint64_t beg = 0, len = 0;
7354
7355 /* Count positional arguments so that an explicit nil is not mistaken for an omitted one. */
7356 int nargs = rb_scan_args(argc, argv, "02:", &v0, &v1, &opts);
7357 /*
7358 * A whole-string popcount is independent of bit numbering.
7359 * no-(offset|range)-argument form only validates lsb_first.
7360 */
7361 bool lsb_first = str_lsb_first_from_opts(opts);
7362
7363 if (nargs == 0) {
7364 return ULL2NUM(str_count_bits((const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7365 }
7366
7367 bool is_range = rb_obj_is_kind_of(v0, rb_cRange);
7368 struct str_bit_range range = {0};
7369 if (is_range) {
7370 if (nargs == 2) {
7371 rb_raise(rb_eArgError, "bit length not allowed with a Range");
7372 }
7373 str_bit_range_to_offsets(v0, &range);
7374 }
7375 else if (nargs == 1) {
7376 rb_raise(rb_eArgError, "no bit length given");
7377 }
7378 else {
7379 beg = str_bit_offset_from_index(v0).value;
7380 len = str_bit_length_from_index(v1);
7381 }
7382
7383 const unsigned char *ptr = (const unsigned char *)RSTRING_PTR(str);
7384 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7385 if (is_range) {
7386 if (!str_bit_range_resolve(&range, total_bits, &beg, &len)) {
7387 return INT2FIX(0);
7388 }
7389 }
7390 else if (beg >= total_bits) {
7391 return INT2FIX(0);
7392 }
7393
7394 /* Reads clamp: only the part of the region that exists is counted. */
7395 if (len > total_bits - beg) len = total_bits - beg;
7396 if (len == 0) return INT2FIX(0);
7397 return ULL2NUM(str_count_bits_region(ptr, beg, len, lsb_first));
7398}
7399
7400static void
7401str_check_bitwise_length(VALUE str, VALUE other)
7402{
7403 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7404 rb_raise(rb_eArgError, "operands must have the same length (%ld vs %ld)",
7405 RSTRING_LEN(str), RSTRING_LEN(other));
7406 }
7407}
7408
7409static VALUE
7410str_bitwise_result(VALUE str)
7411{
7412 long len = RSTRING_LEN(str);
7413 VALUE result = rb_str_buf_new(len);
7414 rb_str_resize(result, len);
7415 rb_enc_associate(result, rb_ascii8bit_encoding());
7416 ENC_CODERANGE_CLEAR(result);
7417 return result;
7418}
7419
7420#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7421 static void \
7422 name(unsigned char *dst, const unsigned char *src, long len) \
7423 { \
7424 long off = 0; \
7425 long unrolled_end = len & ~31L; \
7426 long aligned_end = len & ~7L; \
7427 for (; off < unrolled_end; off += 32) { \
7428 uint64_t s0, s1, s2, s3; \
7429 memcpy(&s0, src + off, 8); \
7430 memcpy(&s1, src + off + 8, 8); \
7431 memcpy(&s2, src + off + 16, 8); \
7432 memcpy(&s3, src + off + 24, 8); \
7433 s0 = (expr_word(s0)); \
7434 s1 = (expr_word(s1)); \
7435 s2 = (expr_word(s2)); \
7436 s3 = (expr_word(s3)); \
7437 memcpy(dst + off, &s0, 8); \
7438 memcpy(dst + off + 8, &s1, 8); \
7439 memcpy(dst + off + 16, &s2, 8); \
7440 memcpy(dst + off + 24, &s3, 8); \
7441 } \
7442 for (; off < aligned_end; off += 8) { \
7443 uint64_t word; \
7444 memcpy(&word, src + off, 8); \
7445 word = (expr_word(word)); \
7446 memcpy(dst + off, &word, 8); \
7447 } \
7448 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7449 }
7450
7451#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7452 static void \
7453 name(unsigned char *dst, const unsigned char *lhs, \
7454 const unsigned char *rhs, long len) \
7455 { \
7456 long off = 0; \
7457 long unrolled_end = len & ~31L; \
7458 long aligned_end = len & ~7L; \
7459 for (; off < unrolled_end; off += 32) { \
7460 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7461 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7462 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7463 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7464 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7465 l0 = expr_word(l0, r0); \
7466 l1 = expr_word(l1, r1); \
7467 l2 = expr_word(l2, r2); \
7468 l3 = expr_word(l3, r3); \
7469 memcpy(dst + off, &l0, 8); \
7470 memcpy(dst + off + 8, &l1, 8); \
7471 memcpy(dst + off + 16, &l2, 8); \
7472 memcpy(dst + off + 24, &l3, 8); \
7473 } \
7474 for (; off < aligned_end; off += 8) { \
7475 uint64_t lhs_word, rhs_word; \
7476 memcpy(&lhs_word, lhs + off, 8); \
7477 memcpy(&rhs_word, rhs + off, 8); \
7478 lhs_word = expr_word(lhs_word, rhs_word); \
7479 memcpy(dst + off, &lhs_word, 8); \
7480 } \
7481 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7482 }
7483
7484#define STR_BITWISE_NOT_WORD(x) (~(x))
7485#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7486#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7487#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7488#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7489#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7490#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7491#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7492
7493STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7494STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7495STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7496STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7497
7498/*
7499 * call-seq:
7500 * bitwise_not -> string
7501 *
7502 * :include: doc/string/bitwise_not.rdoc
7503 *
7504 */
7505static VALUE
7506rb_str_bitwise_not(VALUE str)
7507{
7508 long len = RSTRING_LEN(str);
7509 VALUE result = str_bitwise_result(str);
7510 str_bitwise_not((unsigned char *)RSTRING_PTR(result),
7511 (const unsigned char *)RSTRING_PTR(str), len);
7512 return result;
7513}
7514
7515/*
7516 * call-seq:
7517 * bitwise_not! -> self
7518 *
7519 * :include: doc/string/bitwise_not_bang.rdoc
7520 *
7521 */
7522static VALUE
7523rb_str_bitwise_not_bang(VALUE str)
7524{
7525 long len;
7526 unsigned char *ptr;
7527
7528 rb_str_modify(str);
7529 len = RSTRING_LEN(str);
7530 ptr = (unsigned char *)RSTRING_PTR(str);
7531 str_bitwise_not(ptr, ptr, len);
7532 return str;
7533}
7534
7535#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7536 static VALUE \
7537 rb_str_bitwise_##name(VALUE str, VALUE other) \
7538 { \
7539 long len; \
7540 VALUE result; \
7541 StringValue(other); \
7542 str_check_bitwise_length(str, other); \
7543 len = RSTRING_LEN(str); \
7544 result = str_bitwise_result(str); \
7545 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7546 (const unsigned char *)RSTRING_PTR(str), \
7547 (const unsigned char *)RSTRING_PTR(other), len); \
7548 return result; \
7549 } \
7550 static VALUE \
7551 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7552 { \
7553 long len; \
7554 unsigned char *ptr; \
7555 StringValue(other); \
7556 str_check_bitwise_length(str, other); \
7557 rb_str_modify(str); \
7558 len = RSTRING_LEN(str); \
7559 ptr = (unsigned char *)RSTRING_PTR(str); \
7560 str_bitwise_##name(ptr, ptr, \
7561 (const unsigned char *)RSTRING_PTR(other), len); \
7562 return str; \
7563 }
7564
7565STR_DEFINE_BINARY_BITWISE_METHOD(and)
7566STR_DEFINE_BINARY_BITWISE_METHOD(or)
7567STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7568
7569static VALUE
7570str_byte_substr(VALUE str, long beg, long len, int empty)
7571{
7572 long n = RSTRING_LEN(str);
7573
7574 if (beg > n || len < 0) return Qnil;
7575 if (beg < 0) {
7576 beg += n;
7577 if (beg < 0) return Qnil;
7578 }
7579 if (len > n - beg)
7580 len = n - beg;
7581 if (len <= 0) {
7582 if (!empty) return Qnil;
7583 len = 0;
7584 }
7585
7586 VALUE str2 = str_subseq(str, beg, len);
7587
7588 str_enc_copy_direct(str2, str);
7589
7590 if (RSTRING_LEN(str2) == 0) {
7591 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7593 else
7595 }
7596 else {
7597 switch (ENC_CODERANGE(str)) {
7598 case ENC_CODERANGE_7BIT:
7600 break;
7601 default:
7603 break;
7604 }
7605 }
7606
7607 return str2;
7608}
7609
7610VALUE
7611rb_str_byte_substr(VALUE str, VALUE beg, VALUE len)
7612{
7613 return str_byte_substr(str, NUM2LONG(beg), NUM2LONG(len), TRUE);
7614}
7615
7616static VALUE
7617str_byte_aref(VALUE str, VALUE indx)
7618{
7619 long idx;
7620 if (FIXNUM_P(indx)) {
7621 idx = FIX2LONG(indx);
7622 }
7623 else {
7624 /* check if indx is Range */
7625 long beg, len = RSTRING_LEN(str);
7626
7627 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
7628 case Qfalse:
7629 break;
7630 case Qnil:
7631 return Qnil;
7632 default:
7633 return str_byte_substr(str, beg, len, TRUE);
7634 }
7635
7636 idx = NUM2LONG(indx);
7637 }
7638 return str_byte_substr(str, idx, 1, FALSE);
7639}
7640
7641/*
7642 * call-seq:
7643 * byteslice(offset, length = 1) -> string or nil
7644 * byteslice(range) -> string or nil
7645 *
7646 * :include: doc/string/byteslice.rdoc
7647 */
7648
7649static VALUE
7650rb_str_byteslice(int argc, VALUE *argv, VALUE str)
7651{
7652 if (argc == 2) {
7653 long beg = NUM2LONG(argv[0]);
7654 long len = NUM2LONG(argv[1]);
7655 return str_byte_substr(str, beg, len, TRUE);
7656 }
7657 rb_check_arity(argc, 1, 2);
7658 return str_byte_aref(str, argv[0]);
7659}
7660
7661static void
7662str_check_beg_len(VALUE str, long *beg, long *len)
7663{
7664 long end, slen = RSTRING_LEN(str);
7665
7666 if (*len < 0) rb_raise(rb_eIndexError, "negative length %ld", *len);
7667 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7668 rb_raise(rb_eIndexError, "index %ld out of string", *beg);
7669 }
7670 if (*beg < 0) {
7671 *beg += slen;
7672 }
7673 RUBY_ASSERT(*beg >= 0);
7674 RUBY_ASSERT(*beg <= slen);
7675
7676 if (*len > slen - *beg) {
7677 *len = slen - *beg;
7678 }
7679 end = *beg + *len;
7680 str_ensure_byte_pos(str, *beg);
7681 str_ensure_byte_pos(str, end);
7682}
7683
7684/*
7685 * call-seq:
7686 * bytesplice(offset, length, str) -> self
7687 * bytesplice(offset, length, str, str_offset, str_length) -> self
7688 * bytesplice(range, str) -> self
7689 * bytesplice(range, str, str_range) -> self
7690 *
7691 * :include: doc/string/bytesplice.rdoc
7692 */
7693
7694static VALUE
7695rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
7696{
7697 long beg, len, vbeg, vlen;
7698 VALUE val;
7699 int cr;
7700
7701 rb_check_arity(argc, 2, 5);
7702 if (!(argc == 2 || argc == 3 || argc == 5)) {
7703 rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7704 }
7705 if (argc == 2 || (argc == 3 && !RB_INTEGER_TYPE_P(argv[0]))) {
7706 if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
7707 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7708 rb_builtin_class_name(argv[0]));
7709 }
7710 val = argv[1];
7711 StringValue(val);
7712 if (argc == 2) {
7713 /* bytesplice(range, str) */
7714 vbeg = 0;
7715 vlen = RSTRING_LEN(val);
7716 }
7717 else {
7718 /* bytesplice(range, str, str_range) */
7719 if (!rb_range_beg_len(argv[2], &vbeg, &vlen, RSTRING_LEN(val), 2)) {
7720 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7721 rb_builtin_class_name(argv[2]));
7722 }
7723 }
7724 }
7725 else {
7726 beg = NUM2LONG(argv[0]);
7727 len = NUM2LONG(argv[1]);
7728 val = argv[2];
7729 StringValue(val);
7730 if (argc == 3) {
7731 /* bytesplice(index, length, str) */
7732 vbeg = 0;
7733 vlen = RSTRING_LEN(val);
7734 }
7735 else {
7736 /* bytesplice(index, length, str, str_index, str_length) */
7737 vbeg = NUM2LONG(argv[3]);
7738 vlen = NUM2LONG(argv[4]);
7739 }
7740 }
7741 str_check_beg_len(str, &beg, &len);
7742 str_check_beg_len(val, &vbeg, &vlen);
7743 str_modify_keep_cr(str);
7744
7745 if (RB_UNLIKELY(ENCODING_GET_INLINED(str) != ENCODING_GET_INLINED(val))) {
7746 rb_enc_associate(str, rb_enc_check(str, val));
7747 }
7748
7749 rb_str_update_1(str, beg, len, val, vbeg, vlen);
7751 if (cr != ENC_CODERANGE_BROKEN)
7752 ENC_CODERANGE_SET(str, cr);
7753 return str;
7754}
7755
7756/*
7757 * call-seq:
7758 * reverse -> new_string
7759 *
7760 * Returns a new string with the characters from +self+ in reverse order.
7761 *
7762 * 'drawer'.reverse # => "reward"
7763 * 'reviled'.reverse # => "deliver"
7764 * 'stressed'.reverse # => "desserts"
7765 * 'semordnilaps'.reverse # => "spalindromes"
7766 *
7767 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7768 */
7769
7770static VALUE
7771rb_str_reverse(VALUE str)
7772{
7773 rb_encoding *enc;
7774 VALUE rev;
7775 char *s, *e, *p;
7776 int cr;
7777
7778 if (RSTRING_LEN(str) <= 1) return str_duplicate(rb_cString, str);
7779 enc = STR_ENC_GET(str);
7780 rev = rb_str_new(0, RSTRING_LEN(str));
7781 s = RSTRING_PTR(str); e = RSTRING_END(str);
7782 p = RSTRING_END(rev);
7783 cr = ENC_CODERANGE(str);
7784
7785 if (RSTRING_LEN(str) > 1) {
7786 if (single_byte_optimizable(str)) {
7787 while (s < e) {
7788 *--p = *s++;
7789 }
7790 }
7791 else if (cr == ENC_CODERANGE_VALID) {
7792 while (s < e) {
7793 int clen = rb_enc_fast_mbclen(s, e, enc);
7794
7795 p -= clen;
7796 memcpy(p, s, clen);
7797 s += clen;
7798 }
7799 }
7800 else {
7801 cr = rb_enc_asciicompat(enc) ?
7803 while (s < e) {
7804 int clen = rb_enc_mbclen(s, e, enc);
7805
7806 if (clen > 1 || (*s & 0x80)) cr = ENC_CODERANGE_UNKNOWN;
7807 p -= clen;
7808 memcpy(p, s, clen);
7809 s += clen;
7810 }
7811 }
7812 }
7813 STR_SET_LEN(rev, RSTRING_LEN(str));
7814 str_enc_copy_direct(rev, str);
7815 ENC_CODERANGE_SET(rev, cr);
7816
7817 return rev;
7818}
7819
7820
7821/*
7822 * call-seq:
7823 * reverse! -> self
7824 *
7825 * Returns +self+ with its characters reversed:
7826 *
7827 * 'drawer'.reverse! # => "reward"
7828 * 'reviled'.reverse! # => "deliver"
7829 * 'stressed'.reverse! # => "desserts"
7830 * 'semordnilaps'.reverse! # => "spalindromes"
7831 *
7832 * Related: see {Modifying}[rdoc-ref:String@Modifying].
7833 */
7834
7835static VALUE
7836rb_str_reverse_bang(VALUE str)
7837{
7838 if (RSTRING_LEN(str) > 1) {
7839 if (single_byte_optimizable(str)) {
7840 char *s, *e, c;
7841
7842 str_modify_keep_cr(str);
7843 s = RSTRING_PTR(str);
7844 e = RSTRING_END(str) - 1;
7845 while (s < e) {
7846 c = *s;
7847 *s++ = *e;
7848 *e-- = c;
7849 }
7850 }
7851 else {
7852 str_shared_replace(str, rb_str_reverse(str));
7853 }
7854 }
7855 else {
7856 str_modify_keep_cr(str);
7857 }
7858 return str;
7859}
7860
7861
7862/*
7863 * call-seq:
7864 * include?(other_string) -> true or false
7865 *
7866 * Returns whether +self+ contains +other_string+:
7867 *
7868 * s = 'bar'
7869 * s.include?('ba') # => true
7870 * s.include?('ar') # => true
7871 * s.include?('bar') # => true
7872 * s.include?('a') # => true
7873 * s.include?('') # => true
7874 * s.include?('foo') # => false
7875 *
7876 * Related: see {Querying}[rdoc-ref:String@Querying].
7877 */
7878
7879VALUE
7880rb_str_include(VALUE str, VALUE arg)
7881{
7882 long i;
7883
7884 StringValue(arg);
7885 i = rb_str_index(str, arg, 0);
7886
7887 return RBOOL(i != -1);
7888}
7889
7890
7891/*
7892 * call-seq:
7893 * to_i(base = 10) -> integer
7894 *
7895 * Returns the result of interpreting leading characters in +self+
7896 * as an integer in the given +base+;
7897 * +base+ must be either +0+ or in range <tt>(2..36)</tt>:
7898 *
7899 * '123456'.to_i # => 123456
7900 * '123def'.to_i(16) # => 1195503
7901 *
7902 * With +base+ zero given, string +object+ may contain leading characters
7903 * to specify the actual base:
7904 *
7905 * '123def'.to_i(0) # => 123
7906 * '0123def'.to_i(0) # => 83
7907 * '0b123def'.to_i(0) # => 1
7908 * '0o123def'.to_i(0) # => 83
7909 * '0d123def'.to_i(0) # => 123
7910 * '0x123def'.to_i(0) # => 1195503
7911 *
7912 * Characters past a leading valid number (in the given +base+) are ignored:
7913 *
7914 * '12.345'.to_i # => 12
7915 * '12345'.to_i(2) # => 1
7916 *
7917 * Returns zero if there is no leading valid number:
7918 *
7919 * 'abcdef'.to_i # => 0
7920 * '2'.to_i(2) # => 0
7921 *
7922 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
7923 */
7924
7925static VALUE
7926rb_str_to_i(int argc, VALUE *argv, VALUE str)
7927{
7928 int base = 10;
7929
7930 if (rb_check_arity(argc, 0, 1) && (base = NUM2INT(argv[0])) < 0) {
7931 rb_raise(rb_eArgError, "invalid radix %d", base);
7932 }
7933 return rb_str_to_inum(str, base, FALSE);
7934}
7935
7936
7937/*
7938 * call-seq:
7939 * to_f -> float
7940 *
7941 * Returns the result of interpreting leading characters in +self+ as a Float:
7942 *
7943 * '3.14159'.to_f # => 3.14159
7944 * '1.234e-2'.to_f # => 0.01234
7945 *
7946 * Characters past a leading valid number are ignored:
7947 *
7948 * '3.14 (pi to two places)'.to_f # => 3.14
7949 *
7950 * Returns zero if there is no leading valid number:
7951 *
7952 * 'abcdef'.to_f # => 0.0
7953 *
7954 * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
7955 */
7956
7957static VALUE
7958rb_str_to_f(VALUE str)
7959{
7960 return DBL2NUM(rb_str_to_dbl(str, FALSE));
7961}
7962
7963
7964/*
7965 * call-seq:
7966 * to_s -> self or new_string
7967 *
7968 * Returns +self+ if +self+ is a +String+,
7969 * or +self+ converted to a +String+ if +self+ is a subclass of +String+.
7970 *
7971 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7972 */
7973
7974static VALUE
7975rb_str_to_s(VALUE str)
7976{
7977 if (rb_obj_class(str) != rb_cString) {
7978 return str_duplicate(rb_cString, str);
7979 }
7980 return str;
7981}
7982
7983#if 0
7984static void
7985str_cat_char(VALUE str, unsigned int c, rb_encoding *enc)
7986{
7987 char s[RUBY_MAX_CHAR_LEN];
7988 int n = rb_enc_codelen(c, enc);
7989
7990 rb_enc_mbcput(c, s, enc);
7991 rb_enc_str_buf_cat(str, s, n, enc);
7992}
7993#endif
7994
7995#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */
7996
7997int
7998rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p)
7999{
8000 char buf[CHAR_ESC_LEN + 1];
8001 int l;
8002
8003#if SIZEOF_INT > 4
8004 c &= 0xffffffff;
8005#endif
8006 if (unicode_p) {
8007 if (c < 0x7F && ISPRINT(c)) {
8008 snprintf(buf, CHAR_ESC_LEN, "%c", c);
8009 }
8010 else if (c < 0x10000) {
8011 snprintf(buf, CHAR_ESC_LEN, "\\u%04X", c);
8012 }
8013 else {
8014 snprintf(buf, CHAR_ESC_LEN, "\\u{%X}", c);
8015 }
8016 }
8017 else {
8018 if (c < 0x100) {
8019 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", c);
8020 }
8021 else {
8022 snprintf(buf, CHAR_ESC_LEN, "\\x{%X}", c);
8023 }
8024 }
8025 l = (int)strlen(buf); /* CHAR_ESC_LEN cannot exceed INT_MAX */
8026 rb_str_buf_cat(result, buf, l);
8027 return l;
8028}
8029
8030const char *
8031ruby_escaped_char(int c)
8032{
8033 switch (c) {
8034 case '\0': return "\\0";
8035 case '\n': return "\\n";
8036 case '\r': return "\\r";
8037 case '\t': return "\\t";
8038 case '\f': return "\\f";
8039 case '\013': return "\\v";
8040 case '\010': return "\\b";
8041 case '\007': return "\\a";
8042 case '\033': return "\\e";
8043 case '\x7f': return "\\c?";
8044 }
8045 return NULL;
8046}
8047
8048VALUE
8049rb_str_escape(VALUE str)
8050{
8051 int encidx = ENCODING_GET(str);
8052 rb_encoding *enc = rb_enc_from_index(encidx);
8053 const char *p = RSTRING_PTR(str);
8054 const char *pend = RSTRING_END(str);
8055 const char *prev = p;
8056 char buf[CHAR_ESC_LEN + 1];
8057 VALUE result = rb_str_buf_new(0);
8058 int unicode_p = rb_enc_unicode_p(enc);
8059 int asciicompat = rb_enc_asciicompat(enc);
8060
8061 while (p < pend) {
8062 unsigned int c;
8063 const char *cc;
8064 int n = rb_enc_precise_mbclen(p, pend, enc);
8065 if (!MBCLEN_CHARFOUND_P(n)) {
8066 if (p > prev) str_buf_cat(result, prev, p - prev);
8067 n = rb_enc_mbminlen(enc);
8068 if (pend < p + n)
8069 n = (int)(pend - p);
8070 while (n--) {
8071 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
8072 str_buf_cat(result, buf, strlen(buf));
8073 prev = ++p;
8074 }
8075 continue;
8076 }
8077 n = MBCLEN_CHARFOUND_LEN(n);
8078 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8079 p += n;
8080 cc = ruby_escaped_char(c);
8081 if (cc) {
8082 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8083 str_buf_cat(result, cc, strlen(cc));
8084 prev = p;
8085 }
8086 else if (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c)) {
8087 }
8088 else {
8089 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8090 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8091 prev = p;
8092 }
8093 }
8094 if (p > prev) str_buf_cat(result, prev, p - prev);
8095 ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
8096
8097 return result;
8098}
8099
8100/* Lookup table for the inspect fast path. 1 marks bytes that need
8101 * no escaping. 0 marks bytes that need escape inspection: 0x00-0x1F
8102 * (control), 0x22 ("), 0x23 (#), 0x5C (\‍), 0x7F (DEL), 0x80-0xFF
8103 * (non-ASCII). */
8104static const bool inspect_no_escape[256] = {
8105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
8106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
8107 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20-0x2F */
8108 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30-0x3F */
8109 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F */
8110 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 0x50-0x5F */
8111 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F */
8112 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 0x70-0x7F */
8113};
8114
8115/*
8116 * call-seq:
8117 * inspect -> string
8118 *
8119 * :include: doc/string/inspect.rdoc
8120 *
8121 */
8122
8123VALUE
8125{
8126 int encidx = ENCODING_GET(str);
8127 rb_encoding *enc = rb_enc_from_index(encidx);
8128 const char *p, *pend, *prev;
8129 char buf[CHAR_ESC_LEN + 1];
8130 VALUE result = rb_str_buf_new(RSTRING_LEN(str) + 2); /* string content + surrounding quotes */
8131 rb_encoding *resenc = rb_default_internal_encoding();
8132 int unicode_p = rb_enc_unicode_p(enc);
8133 int asciicompat = rb_enc_asciicompat(enc);
8134 int cr = rb_enc_str_coderange(str);
8135
8136 if (resenc == NULL) resenc = rb_default_external_encoding();
8137 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8138 rb_enc_associate(result, resenc);
8139 str_buf_cat2(result, "\"");
8140
8141 p = RSTRING_PTR(str); pend = RSTRING_END(str);
8142 prev = p;
8143 while (p < pend) {
8144 unsigned int c, cc;
8145 int n;
8146
8147 /* Fast path: bulk-skip runs of safe ASCII bytes via a lookup table.
8148 * Only well-formed strings (CR=7BIT for any encoding, or UTF-8 VALID)
8149 * are eligible. */
8150 if (cr == ENC_CODERANGE_7BIT ||
8151 (encidx == ENCINDEX_UTF_8 && cr == ENC_CODERANGE_VALID)) {
8152 while (p < pend && inspect_no_escape[(unsigned char)*p]) p++;
8153 if (p >= pend) break;
8154 }
8155
8156 n = rb_enc_precise_mbclen(p, pend, enc);
8157 if (!MBCLEN_CHARFOUND_P(n)) {
8158 if (p > prev) str_buf_cat(result, prev, p - prev);
8159 n = rb_enc_mbminlen(enc);
8160 if (pend < p + n)
8161 n = (int)(pend - p);
8162 while (n--) {
8163 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
8164 str_buf_cat(result, buf, strlen(buf));
8165 prev = ++p;
8166 }
8167 continue;
8168 }
8169 n = MBCLEN_CHARFOUND_LEN(n);
8170 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8171 p += n;
8172 if ((asciicompat || unicode_p) &&
8173 (c == '"'|| c == '\\' ||
8174 (c == '#' &&
8175 p < pend &&
8176 MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
8177 (cc = rb_enc_codepoint(p,pend,enc),
8178 (cc == '$' || cc == '@' || cc == '{'))))) {
8179 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8180 str_buf_cat2(result, "\\");
8181 if (asciicompat || enc == resenc) {
8182 prev = p - n;
8183 continue;
8184 }
8185 }
8186 switch (c) {
8187 case '\n': cc = 'n'; break;
8188 case '\r': cc = 'r'; break;
8189 case '\t': cc = 't'; break;
8190 case '\f': cc = 'f'; break;
8191 case '\013': cc = 'v'; break;
8192 case '\010': cc = 'b'; break;
8193 case '\007': cc = 'a'; break;
8194 case 033: cc = 'e'; break;
8195 default: cc = 0; break;
8196 }
8197 if (cc) {
8198 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8199 buf[0] = '\\';
8200 buf[1] = (char)cc;
8201 str_buf_cat(result, buf, 2);
8202 prev = p;
8203 continue;
8204 }
8205 /* The special casing of 0x85 (NEXT_LINE) here is because
8206 * Oniguruma historically treats it as printable, but it
8207 * doesn't match the print POSIX bracket class or character
8208 * property in regexps.
8209 *
8210 * See Ruby Bug #16842 for details:
8211 * https://bugs.ruby-lang.org/issues/16842
8212 */
8213 if ((enc == resenc && rb_enc_isprint(c, enc) && c != 0x85) ||
8214 (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c))) {
8215 continue;
8216 }
8217 else {
8218 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8219 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8220 prev = p;
8221 continue;
8222 }
8223 }
8224 if (p > prev) str_buf_cat(result, prev, p - prev);
8225 str_buf_cat2(result, "\"");
8226
8227 return result;
8228}
8229
8230#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8231
8232/*
8233 * call-seq:
8234 * dump -> new_string
8235 *
8236 * :include: doc/string/dump.rdoc
8237 *
8238 */
8239
8240VALUE
8242{
8243 int encidx = rb_enc_get_index(str);
8244 rb_encoding *enc = rb_enc_from_index(encidx);
8245 long len;
8246 const char *p, *pend;
8247 char *q, *qend;
8248 VALUE result;
8249 int u8 = (encidx == rb_utf8_encindex());
8250 static const char nonascii_suffix[] = ".dup.force_encoding(\"%s\")";
8251
8252 len = 2; /* "" */
8253 if (!rb_enc_asciicompat(enc)) {
8254 len += strlen(nonascii_suffix) - rb_strlen_lit("%s");
8255 len += strlen(enc->name);
8256 }
8257
8258 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8259 while (p < pend) {
8260 int clen;
8261 unsigned char c = *p++;
8262
8263 switch (c) {
8264 case '"': case '\\':
8265 case '\n': case '\r':
8266 case '\t': case '\f':
8267 case '\013': case '\010': case '\007': case '\033':
8268 clen = 2;
8269 break;
8270
8271 case '#':
8272 clen = IS_EVSTR(p, pend) ? 2 : 1;
8273 break;
8274
8275 default:
8276 if (ISPRINT(c)) {
8277 clen = 1;
8278 }
8279 else {
8280 if (u8 && c > 0x7F) { /* \u notation */
8281 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8282 if (MBCLEN_CHARFOUND_P(n)) {
8283 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8284 if (cc <= 0xFFFF)
8285 clen = 6; /* \uXXXX */
8286 else if (cc <= 0xFFFFF)
8287 clen = 9; /* \u{XXXXX} */
8288 else
8289 clen = 10; /* \u{XXXXXX} */
8290 p += MBCLEN_CHARFOUND_LEN(n)-1;
8291 break;
8292 }
8293 }
8294 clen = 4; /* \xNN */
8295 }
8296 break;
8297 }
8298
8299 if (clen > LONG_MAX - len) {
8300 rb_raise(rb_eRuntimeError, "string size too big");
8301 }
8302 len += clen;
8303 }
8304
8305 result = rb_str_new(0, len);
8306 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8307 q = RSTRING_PTR(result); qend = q + len + 1;
8308
8309 *q++ = '"';
8310 while (p < pend) {
8311 unsigned char c = *p++;
8312
8313 if (c == '"' || c == '\\') {
8314 *q++ = '\\';
8315 *q++ = c;
8316 }
8317 else if (c == '#') {
8318 if (IS_EVSTR(p, pend)) *q++ = '\\';
8319 *q++ = '#';
8320 }
8321 else if (c == '\n') {
8322 *q++ = '\\';
8323 *q++ = 'n';
8324 }
8325 else if (c == '\r') {
8326 *q++ = '\\';
8327 *q++ = 'r';
8328 }
8329 else if (c == '\t') {
8330 *q++ = '\\';
8331 *q++ = 't';
8332 }
8333 else if (c == '\f') {
8334 *q++ = '\\';
8335 *q++ = 'f';
8336 }
8337 else if (c == '\013') {
8338 *q++ = '\\';
8339 *q++ = 'v';
8340 }
8341 else if (c == '\010') {
8342 *q++ = '\\';
8343 *q++ = 'b';
8344 }
8345 else if (c == '\007') {
8346 *q++ = '\\';
8347 *q++ = 'a';
8348 }
8349 else if (c == '\033') {
8350 *q++ = '\\';
8351 *q++ = 'e';
8352 }
8353 else if (ISPRINT(c)) {
8354 *q++ = c;
8355 }
8356 else {
8357 *q++ = '\\';
8358 if (u8) {
8359 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8360 if (MBCLEN_CHARFOUND_P(n)) {
8361 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8362 p += n;
8363 if (cc <= 0xFFFF)
8364 snprintf(q, qend-q, "u%04X", cc); /* \uXXXX */
8365 else
8366 snprintf(q, qend-q, "u{%X}", cc); /* \u{XXXXX} or \u{XXXXXX} */
8367 q += strlen(q);
8368 continue;
8369 }
8370 }
8371 snprintf(q, qend-q, "x%02X", c);
8372 q += 3;
8373 }
8374 }
8375 *q++ = '"';
8376 *q = '\0';
8377 if (!rb_enc_asciicompat(enc)) {
8378 snprintf(q, qend-q, nonascii_suffix, enc->name);
8379 encidx = rb_ascii8bit_encindex();
8380 }
8381 /* result from dump is ASCII */
8382 rb_enc_associate_index(result, encidx);
8384 return result;
8385}
8386
8387static int
8388unescape_ascii(unsigned int c)
8389{
8390 switch (c) {
8391 case 'n':
8392 return '\n';
8393 case 'r':
8394 return '\r';
8395 case 't':
8396 return '\t';
8397 case 'f':
8398 return '\f';
8399 case 'v':
8400 return '\13';
8401 case 'b':
8402 return '\010';
8403 case 'a':
8404 return '\007';
8405 case 'e':
8406 return 033;
8407 }
8409}
8410
8411static void
8412undump_after_backslash(VALUE undumped, const char **ss, const char *s_end, rb_encoding **penc, bool *utf8, bool *binary)
8413{
8414 const char *s = *ss;
8415 unsigned int c;
8416 int codelen;
8417 size_t hexlen;
8418 unsigned char buf[6];
8419 static rb_encoding *enc_utf8 = NULL;
8420
8421 switch (*s) {
8422 case '\\':
8423 case '"':
8424 case '#':
8425 rb_str_cat(undumped, s, 1); /* cat itself */
8426 s++;
8427 break;
8428 case 'n':
8429 case 'r':
8430 case 't':
8431 case 'f':
8432 case 'v':
8433 case 'b':
8434 case 'a':
8435 case 'e':
8436 *buf = unescape_ascii(*s);
8437 rb_str_cat(undumped, (char *)buf, 1);
8438 s++;
8439 break;
8440 case 'u':
8441 if (*binary) {
8442 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8443 }
8444 *utf8 = true;
8445 if (++s >= s_end) {
8446 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8447 }
8448 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8449 if (*penc != enc_utf8) {
8450 *penc = enc_utf8;
8451 rb_enc_associate(undumped, enc_utf8);
8452 }
8453 if (*s == '{') { /* handle \u{...} form */
8454 s++;
8455 for (;;) {
8456 if (s >= s_end) {
8457 rb_raise(rb_eRuntimeError, "unterminated Unicode escape");
8458 }
8459 if (*s == '}') {
8460 s++;
8461 break;
8462 }
8463 if (ISSPACE(*s)) {
8464 s++;
8465 continue;
8466 }
8467 c = scan_hex(s, s_end-s, &hexlen);
8468 if (hexlen == 0 || hexlen > 6) {
8469 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8470 }
8471 if (c > 0x10ffff) {
8472 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint (too large)");
8473 }
8474 if (0xd800 <= c && c <= 0xdfff) {
8475 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8476 }
8477 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8478 rb_str_cat(undumped, (char *)buf, codelen);
8479 s += hexlen;
8480 }
8481 }
8482 else { /* handle \uXXXX form */
8483 c = scan_hex(s, 4, &hexlen);
8484 if (hexlen != 4) {
8485 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8486 }
8487 if (0xd800 <= c && c <= 0xdfff) {
8488 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8489 }
8490 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8491 rb_str_cat(undumped, (char *)buf, codelen);
8492 s += hexlen;
8493 }
8494 break;
8495 case 'x':
8496 if (++s >= s_end) {
8497 rb_raise(rb_eRuntimeError, "invalid hex escape");
8498 }
8499 *buf = scan_hex(s, 2, &hexlen);
8500 if (hexlen != 2) {
8501 rb_raise(rb_eRuntimeError, "invalid hex escape");
8502 }
8503 if (!ISASCII(*buf)) {
8504 if (*utf8) {
8505 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8506 }
8507 *binary = true;
8508 }
8509 rb_str_cat(undumped, (char *)buf, 1);
8510 s += hexlen;
8511 break;
8512 default:
8513 rb_str_cat(undumped, s-1, 2);
8514 s++;
8515 }
8516
8517 *ss = s;
8518}
8519
8520static VALUE rb_str_is_ascii_only_p(VALUE str);
8521
8522/*
8523 * call-seq:
8524 * undump -> new_string
8525 *
8526 * Inverse of String#dump; returns a copy of +self+ with changes of the kinds made by String#dump "undone."
8527 *
8528 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8529 */
8530
8531static VALUE
8532str_undump(VALUE str)
8533{
8534 const char *s = RSTRING_PTR(str);
8535 const char *s_end = RSTRING_END(str);
8536 rb_encoding *enc = rb_enc_get(str);
8537 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8538 bool utf8 = false;
8539 bool binary = false;
8540 int w;
8541
8543 if (rb_str_is_ascii_only_p(str) == Qfalse) {
8544 rb_raise(rb_eRuntimeError, "non-ASCII character detected");
8545 }
8546 if (!str_null_check(str, &w)) {
8547 rb_raise(rb_eRuntimeError, "string contains null byte");
8548 }
8549 if (RSTRING_LEN(str) < 2) goto invalid_format;
8550 if (*s != '"') goto invalid_format;
8551
8552 /* strip '"' at the start */
8553 s++;
8554
8555 for (;;) {
8556 if (s >= s_end) {
8557 rb_raise(rb_eRuntimeError, "unterminated dumped string");
8558 }
8559
8560 if (*s == '"') {
8561 /* epilogue */
8562 s++;
8563 if (s == s_end) {
8564 /* ascii compatible dumped string */
8565 break;
8566 }
8567 else {
8568 static const char force_encoding_suffix[] = ".force_encoding(\""; /* "\")" */
8569 static const char dup_suffix[] = ".dup";
8570 const char *encname;
8571 int encidx;
8572 ptrdiff_t size;
8573
8574 /* check separately for strings dumped by older versions */
8575 size = sizeof(dup_suffix) - 1;
8576 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8577
8578 size = sizeof(force_encoding_suffix) - 1;
8579 if (s_end - s <= size) goto invalid_format;
8580 if (memcmp(s, force_encoding_suffix, size) != 0) goto invalid_format;
8581 s += size;
8582
8583 if (utf8) {
8584 rb_raise(rb_eRuntimeError, "dumped string contained Unicode escape but used force_encoding");
8585 }
8586
8587 encname = s;
8588 s = memchr(s, '"', s_end-s);
8589 size = s - encname;
8590 if (!s) goto invalid_format;
8591 if (s_end - s != 2) goto invalid_format;
8592 if (s[0] != '"' || s[1] != ')') goto invalid_format;
8593
8594 encidx = rb_enc_find_index2(encname, (long)size);
8595 if (encidx < 0) {
8596 rb_raise(rb_eRuntimeError, "dumped string has unknown encoding name");
8597 }
8598 rb_enc_associate_index(undumped, encidx);
8599 }
8600 break;
8601 }
8602
8603 if (*s == '\\') {
8604 s++;
8605 if (s >= s_end) {
8606 rb_raise(rb_eRuntimeError, "invalid escape");
8607 }
8608 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8609 }
8610 else {
8611 rb_str_cat(undumped, s++, 1);
8612 }
8613 }
8614
8615 RB_GC_GUARD(str);
8616
8617 return undumped;
8618invalid_format:
8619 rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8620}
8621
8622static void
8623rb_str_check_dummy_enc(rb_encoding *enc)
8624{
8625 if (rb_enc_dummy_p(enc)) {
8626 rb_raise(rb_eEncCompatError, "incompatible encoding with this operation: %s",
8627 rb_enc_name(enc));
8628 }
8629}
8630
8631static rb_encoding *
8632str_true_enc(VALUE str)
8633{
8634 rb_encoding *enc = STR_ENC_GET(str);
8635 rb_str_check_dummy_enc(enc);
8636 return enc;
8637}
8638
8639static OnigCaseFoldType
8640check_case_options(int argc, VALUE *argv, OnigCaseFoldType flags)
8641{
8642 if (argc==0)
8643 return flags;
8644 if (argc>2)
8645 rb_raise(rb_eArgError, "too many options");
8646 if (argv[0]==sym_turkic) {
8647 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8648 if (argc==2) {
8649 if (argv[1]==sym_lithuanian)
8650 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8651 else
8652 rb_raise(rb_eArgError, "invalid second option");
8653 }
8654 }
8655 else if (argv[0]==sym_lithuanian) {
8656 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8657 if (argc==2) {
8658 if (argv[1]==sym_turkic)
8659 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8660 else
8661 rb_raise(rb_eArgError, "invalid second option");
8662 }
8663 }
8664 else if (argc>1)
8665 rb_raise(rb_eArgError, "too many options");
8666 else if (argv[0]==sym_ascii)
8667 flags |= ONIGENC_CASE_ASCII_ONLY;
8668 else if (argv[0]==sym_fold) {
8669 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8670 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8671 else
8672 rb_raise(rb_eArgError, "option :fold only allowed for downcasing");
8673 }
8674 else
8675 rb_raise(rb_eArgError, "invalid option");
8676 return flags;
8677}
8678
8679static inline bool
8680case_option_single_p(OnigCaseFoldType flags, rb_encoding *enc, VALUE str)
8681{
8682 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() || rb_enc_mbmaxlen(enc) == 1))
8683 return true;
8684 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8685 (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT || rb_is_ascii8bit_enc(enc));
8686}
8687
8688/* 16 should be long enough to absorb any kind of single character length increase */
8689#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8690#ifndef CASEMAP_DEBUG
8691# define CASEMAP_DEBUG 0
8692#endif
8693
8694struct mapping_buffer;
8695typedef struct mapping_buffer {
8696 size_t capa;
8697 size_t used;
8698 struct mapping_buffer *next;
8699 OnigUChar space[FLEX_ARY_LEN];
8701
8702static void
8703mapping_buffer_free(void *p)
8704{
8705 mapping_buffer *previous_buffer;
8706 mapping_buffer *current_buffer = p;
8707 while (current_buffer) {
8708 previous_buffer = current_buffer;
8709 current_buffer = current_buffer->next;
8710 ruby_xfree_sized(previous_buffer, offsetof(mapping_buffer, space) + previous_buffer->capa);
8711 }
8712}
8713
8714static const rb_data_type_t mapping_buffer_type = {
8715 "mapping_buffer",
8716 {0, mapping_buffer_free,},
8717 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8718};
8719
8720static VALUE
8721rb_str_casemap(VALUE source, OnigCaseFoldType *flags, rb_encoding *enc)
8722{
8723 VALUE target;
8724
8725 const OnigUChar *source_current, *source_end;
8726 int target_length = 0;
8727 VALUE buffer_anchor;
8728 mapping_buffer *current_buffer = 0;
8729 mapping_buffer **pre_buffer;
8730 size_t buffer_count = 0;
8731 int buffer_length_or_invalid;
8732
8733 if (RSTRING_LEN(source) == 0) return str_duplicate(rb_cString, source);
8734
8735 source_current = (OnigUChar*)RSTRING_PTR(source);
8736 source_end = (OnigUChar*)RSTRING_END(source);
8737
8738 buffer_anchor = TypedData_Wrap_Struct(0, &mapping_buffer_type, 0);
8739 pre_buffer = (mapping_buffer **)&DATA_PTR(buffer_anchor);
8740 while (source_current < source_end) {
8741 /* increase multiplier using buffer count to converge quickly */
8742 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8743 if (CASEMAP_DEBUG) {
8744 fprintf(stderr, "Buffer allocation, capa is %"PRIuSIZE"\n", capa); /* for tuning */
8745 }
8746 current_buffer = xmalloc(offsetof(mapping_buffer, space) + capa);
8747 *pre_buffer = current_buffer;
8748 pre_buffer = &current_buffer->next;
8749 current_buffer->next = NULL;
8750 current_buffer->capa = capa;
8751 buffer_length_or_invalid = enc->case_map(flags,
8752 &source_current, source_end,
8753 current_buffer->space,
8754 current_buffer->space+current_buffer->capa,
8755 enc);
8756 if (buffer_length_or_invalid < 0) {
8757 current_buffer = DATA_PTR(buffer_anchor);
8758 DATA_PTR(buffer_anchor) = 0;
8759 mapping_buffer_free(current_buffer);
8760 rb_raise(rb_eArgError, "input string invalid");
8761 }
8762 target_length += current_buffer->used = buffer_length_or_invalid;
8763 }
8764 if (CASEMAP_DEBUG) {
8765 fprintf(stderr, "Buffer count is %"PRIuSIZE"\n", buffer_count); /* for tuning */
8766 }
8767
8768 if (buffer_count==1) {
8769 target = rb_str_new((const char*)current_buffer->space, target_length);
8770 }
8771 else {
8772 char *target_current;
8773
8774 target = rb_str_new(0, target_length);
8775 target_current = RSTRING_PTR(target);
8776 current_buffer = DATA_PTR(buffer_anchor);
8777 while (current_buffer) {
8778 memcpy(target_current, current_buffer->space, current_buffer->used);
8779 target_current += current_buffer->used;
8780 current_buffer = current_buffer->next;
8781 }
8782 }
8783 current_buffer = DATA_PTR(buffer_anchor);
8784 DATA_PTR(buffer_anchor) = 0;
8785 mapping_buffer_free(current_buffer);
8786
8787 RB_GC_GUARD(buffer_anchor);
8788
8789 /* TODO: check about string terminator character */
8790 str_enc_copy_direct(target, source);
8791 /*ENC_CODERANGE_SET(mapped, cr);*/
8792
8793 return target;
8794}
8795
8796static VALUE
8797rb_str_ascii_casemap(VALUE source, VALUE target, OnigCaseFoldType *flags, rb_encoding *enc)
8798{
8799 const OnigUChar *source_current, *source_end;
8800 OnigUChar *target_current, *target_end;
8801 long old_length = RSTRING_LEN(source);
8802 int length_or_invalid;
8803
8804 if (old_length == 0) return Qnil;
8805
8806 source_current = (OnigUChar*)RSTRING_PTR(source);
8807 source_end = (OnigUChar*)RSTRING_END(source);
8808 if (source == target) {
8809 target_current = (OnigUChar*)source_current;
8810 target_end = (OnigUChar*)source_end;
8811 }
8812 else {
8813 target_current = (OnigUChar*)RSTRING_PTR(target);
8814 target_end = (OnigUChar*)RSTRING_END(target);
8815 }
8816
8817 length_or_invalid = onigenc_ascii_only_case_map(flags,
8818 &source_current, source_end,
8819 target_current, target_end, enc);
8820 if (length_or_invalid < 0)
8821 rb_raise(rb_eArgError, "input string invalid");
8822 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8823 fprintf(stderr, "problem with rb_str_ascii_casemap"
8824 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8825 rb_raise(rb_eArgError, "internal problem with rb_str_ascii_casemap"
8826 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8827 }
8828
8829 str_enc_copy(target, source);
8830
8831 return target;
8832}
8833
8834static bool
8835upcase_single(VALUE str)
8836{
8837 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8838 bool modified = false;
8839
8840 while (s < send) {
8841 unsigned int c = *(unsigned char*)s;
8842
8843 if ('a' <= c && c <= 'z') {
8844 *s = 'A' + (c - 'a');
8845 modified = true;
8846 }
8847 s++;
8848 }
8849 return modified;
8850}
8851
8852/*
8853 * call-seq:
8854 * upcase!(mapping) -> self or nil
8855 *
8856 * Like String#upcase, except that:
8857 *
8858 * - Changes character casings in +self+ (not in a copy of +self+).
8859 * - Returns +self+ if any changes are made, +nil+ otherwise.
8860 *
8861 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8862 */
8863
8864static VALUE
8865rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
8866{
8867 rb_encoding *enc;
8868 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8869
8870 flags = check_case_options(argc, argv, flags);
8871 str_modify_keep_cr(str);
8872 enc = str_true_enc(str);
8873 if (case_option_single_p(flags, enc, str)) {
8874 if (upcase_single(str))
8875 flags |= ONIGENC_CASE_MODIFIED;
8876 }
8877 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8878 rb_str_ascii_casemap(str, str, &flags, enc);
8879 else
8880 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8881
8882 if (ONIGENC_CASE_MODIFIED&flags) return str;
8883 return Qnil;
8884}
8885
8886
8887/*
8888 * call-seq:
8889 * upcase(mapping = :ascii) -> new_string
8890 *
8891 * :include: doc/string/upcase.rdoc
8892 */
8893
8894static VALUE
8895rb_str_upcase(int argc, VALUE *argv, VALUE str)
8896{
8897 rb_encoding *enc;
8898 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8899 VALUE ret;
8900
8901 flags = check_case_options(argc, argv, flags);
8902 enc = str_true_enc(str);
8903 if (case_option_single_p(flags, enc, str)) {
8904 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8905 str_enc_copy_direct(ret, str);
8906 upcase_single(ret);
8907 }
8908 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8909 ret = rb_str_new(0, RSTRING_LEN(str));
8910 rb_str_ascii_casemap(str, ret, &flags, enc);
8911 }
8912 else {
8913 ret = rb_str_casemap(str, &flags, enc);
8914 }
8915
8916 return ret;
8917}
8918
8919static bool
8920downcase_single(VALUE str)
8921{
8922 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8923 bool modified = false;
8924
8925 while (s < send) {
8926 unsigned int c = *(unsigned char*)s;
8927
8928 if ('A' <= c && c <= 'Z') {
8929 *s = 'a' + (c - 'A');
8930 modified = true;
8931 }
8932 s++;
8933 }
8934
8935 return modified;
8936}
8937
8938/*
8939 * call-seq:
8940 * downcase!(mapping) -> self or nil
8941 *
8942 * Like String#downcase, except that:
8943 *
8944 * - Changes character casings in +self+ (not in a copy of +self+).
8945 * - Returns +self+ if any changes are made, +nil+ otherwise.
8946 *
8947 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8948 */
8949
8950static VALUE
8951rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
8952{
8953 rb_encoding *enc;
8954 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8955
8956 flags = check_case_options(argc, argv, flags);
8957 str_modify_keep_cr(str);
8958 enc = str_true_enc(str);
8959 if (case_option_single_p(flags, enc, str)) {
8960 if (downcase_single(str))
8961 flags |= ONIGENC_CASE_MODIFIED;
8962 }
8963 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8964 rb_str_ascii_casemap(str, str, &flags, enc);
8965 else
8966 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8967
8968 if (ONIGENC_CASE_MODIFIED&flags) return str;
8969 return Qnil;
8970}
8971
8972
8973/*
8974 * call-seq:
8975 * downcase(mapping = :ascii) -> new_string
8976 *
8977 * :include: doc/string/downcase.rdoc
8978 *
8979 */
8980
8981static VALUE
8982rb_str_downcase(int argc, VALUE *argv, VALUE str)
8983{
8984 rb_encoding *enc;
8985 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8986 VALUE ret;
8987
8988 flags = check_case_options(argc, argv, flags);
8989 enc = str_true_enc(str);
8990 if (case_option_single_p(flags, enc, str)) {
8991 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8992 str_enc_copy_direct(ret, str);
8993 downcase_single(ret);
8994 }
8995 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8996 ret = rb_str_new(0, RSTRING_LEN(str));
8997 rb_str_ascii_casemap(str, ret, &flags, enc);
8998 }
8999 else {
9000 ret = rb_str_casemap(str, &flags, enc);
9001 }
9002
9003 return ret;
9004}
9005
9006static bool
9007capitalize_single(VALUE str)
9008{
9009 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
9010 bool modified = false;
9011
9012 if (s < send) {
9013 unsigned int c = (unsigned char)*s;
9014
9015 if ('a' <= c && c <= 'z') {
9016 *s = 'A' + (c - 'a');
9017 modified = true;
9018 }
9019 s++;
9020 }
9021 while (s < send) {
9022 unsigned int c = (unsigned char)*s;
9023
9024 if ('A' <= c && c <= 'Z') {
9025 *s = 'a' + (c - 'A');
9026 modified = true;
9027 }
9028 s++;
9029 }
9030
9031 return modified;
9032}
9033
9034/*
9035 * call-seq:
9036 * capitalize!(mapping = :ascii) -> self or nil
9037 *
9038 * Like String#capitalize, except that:
9039 *
9040 * - Changes character casings in +self+ (not in a copy of +self+).
9041 * - Returns +self+ if any changes are made, +nil+ otherwise.
9042 *
9043 * Related: See {Modifying}[rdoc-ref:String@Modifying].
9044 */
9045
9046static VALUE
9047rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
9048{
9049 rb_encoding *enc;
9050 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9051
9052 flags = check_case_options(argc, argv, flags);
9053 str_modify_keep_cr(str);
9054 enc = str_true_enc(str);
9055 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
9056 if (case_option_single_p(flags, enc, str)) {
9057 if (capitalize_single(str))
9058 flags |= ONIGENC_CASE_MODIFIED;
9059 }
9060 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9061 rb_str_ascii_casemap(str, str, &flags, enc);
9062 else
9063 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9064
9065 if (ONIGENC_CASE_MODIFIED&flags) return str;
9066 return Qnil;
9067}
9068
9069
9070/*
9071 * call-seq:
9072 * capitalize(mapping = :ascii) -> new_string
9073 *
9074 * :include: doc/string/capitalize.rdoc
9075 *
9076 */
9077
9078static VALUE
9079rb_str_capitalize(int argc, VALUE *argv, VALUE str)
9080{
9081 rb_encoding *enc;
9082 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9083 VALUE ret;
9084
9085 flags = check_case_options(argc, argv, flags);
9086 enc = str_true_enc(str);
9087 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str;
9088 if (case_option_single_p(flags, enc, str)) {
9089 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9090 str_enc_copy_direct(ret, str);
9091 capitalize_single(ret);
9092 }
9093 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9094 ret = rb_str_new(0, RSTRING_LEN(str));
9095 rb_str_ascii_casemap(str, ret, &flags, enc);
9096 }
9097 else {
9098 ret = rb_str_casemap(str, &flags, enc);
9099 }
9100 return ret;
9101}
9102
9103
9104/*
9105 * call-seq:
9106 * swapcase!(mapping) -> self or nil
9107 *
9108 * Like String#swapcase, except that:
9109 *
9110 * - Changes are made to +self+, not to copy of +self+.
9111 * - Returns +self+ if any changes are made, +nil+ otherwise.
9112 *
9113 * Related: see {Modifying}[rdoc-ref:String@Modifying].
9114 */
9115
9116static VALUE
9117rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
9118{
9119 rb_encoding *enc;
9120 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9121
9122 flags = check_case_options(argc, argv, flags);
9123 str_modify_keep_cr(str);
9124 enc = str_true_enc(str);
9125 if (flags&ONIGENC_CASE_ASCII_ONLY)
9126 rb_str_ascii_casemap(str, str, &flags, enc);
9127 else
9128 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9129
9130 if (ONIGENC_CASE_MODIFIED&flags) return str;
9131 return Qnil;
9132}
9133
9134
9135/*
9136 * call-seq:
9137 * swapcase(mapping = :ascii) -> new_string
9138 *
9139 * :include: doc/string/swapcase.rdoc
9140 *
9141 */
9142
9143static VALUE
9144rb_str_swapcase(int argc, VALUE *argv, VALUE str)
9145{
9146 rb_encoding *enc;
9147 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9148 VALUE ret;
9149
9150 flags = check_case_options(argc, argv, flags);
9151 enc = str_true_enc(str);
9152 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str_duplicate(rb_cString, str);
9153 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9154 ret = rb_str_new(0, RSTRING_LEN(str));
9155 rb_str_ascii_casemap(str, ret, &flags, enc);
9156 }
9157 else {
9158 ret = rb_str_casemap(str, &flags, enc);
9159 }
9160 return ret;
9161}
9162
9163typedef unsigned char *USTR;
9164
9165struct tr {
9166 int gen;
9167 unsigned int now, max;
9168 const char *p, *pend;
9169};
9170
9171static unsigned int
9172trnext(struct tr *t, rb_encoding *enc)
9173{
9174 int n;
9175
9176 for (;;) {
9177 nextpart:
9178 if (!t->gen) {
9179 if (t->p == t->pend) return -1;
9180 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '\\' && t->p + n < t->pend) {
9181 t->p += n;
9182 }
9183 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9184 t->p += n;
9185 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '-' && t->p + n < t->pend) {
9186 t->p += n;
9187 if (t->p < t->pend) {
9188 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9189 t->p += n;
9190 if (t->now > c) {
9191 if (t->now < 0x80 && c < 0x80) {
9192 rb_raise(rb_eArgError,
9193 "invalid range \"%c-%c\" in string transliteration",
9194 t->now, c);
9195 }
9196 else {
9197 rb_raise(rb_eArgError, "invalid range in string transliteration");
9198 }
9199 continue; /* not reached */
9200 }
9201 else if (t->now < c) {
9202 t->gen = 1;
9203 t->max = c;
9204 }
9205 }
9206 }
9207 return t->now;
9208 }
9209 else {
9210 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9211 if (t->now == t->max) {
9212 t->gen = 0;
9213 goto nextpart;
9214 }
9215 }
9216 if (t->now < t->max) {
9217 return t->now;
9218 }
9219 else {
9220 t->gen = 0;
9221 return t->max;
9222 }
9223 }
9224 }
9225}
9226
9227static VALUE rb_str_delete_bang(int,VALUE*,VALUE);
9228
9229static VALUE
9230tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
9231{
9232 const unsigned int errc = -1;
9233 unsigned int trans[256];
9234 rb_encoding *enc, *e1, *e2;
9235 struct tr trsrc, trrepl;
9236 int cflag = 0;
9237 unsigned int c, c0, last = 0;
9238 int modify = 0, i, l;
9239 unsigned char *s, *send;
9240 VALUE hash = 0;
9241 int singlebyte = single_byte_optimizable(str);
9242 int termlen;
9243 int cr;
9244
9245#define CHECK_IF_ASCII(c) \
9246 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9247 (cr = ENC_CODERANGE_VALID) : 0)
9248
9249 StringValue(src);
9250 StringValue(repl);
9251 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
9252 if (RSTRING_LEN(repl) == 0) {
9253 return rb_str_delete_bang(1, &src, str);
9254 }
9255
9256 cr = ENC_CODERANGE(str);
9257 e1 = rb_enc_check(str, src);
9258 e2 = rb_enc_check(str, repl);
9259 if (e1 == e2) {
9260 enc = e1;
9261 }
9262 else {
9263 enc = rb_enc_check(src, repl);
9264 }
9265 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9266 if (RSTRING_LEN(src) > 1 &&
9267 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) == '^' &&
9268 trsrc.p + l < trsrc.pend) {
9269 cflag = 1;
9270 trsrc.p += l;
9271 }
9272 trrepl.p = RSTRING_PTR(repl);
9273 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9274 trsrc.gen = trrepl.gen = 0;
9275 trsrc.now = trrepl.now = 0;
9276 trsrc.max = trrepl.max = 0;
9277
9278 if (cflag) {
9279 for (i=0; i<256; i++) {
9280 trans[i] = 1;
9281 }
9282 while ((c = trnext(&trsrc, enc)) != errc) {
9283 if (c < 256) {
9284 trans[c] = errc;
9285 }
9286 else {
9287 if (!hash) hash = rb_hash_new();
9288 rb_hash_aset(hash, UINT2NUM(c), Qtrue);
9289 }
9290 }
9291 while ((c = trnext(&trrepl, enc)) != errc)
9292 /* retrieve last replacer */;
9293 last = trrepl.now;
9294 for (i=0; i<256; i++) {
9295 if (trans[i] != errc) {
9296 trans[i] = last;
9297 }
9298 }
9299 }
9300 else {
9301 unsigned int r;
9302
9303 for (i=0; i<256; i++) {
9304 trans[i] = errc;
9305 }
9306 while ((c = trnext(&trsrc, enc)) != errc) {
9307 r = trnext(&trrepl, enc);
9308 if (r == errc) r = trrepl.now;
9309 if (c < 256) {
9310 trans[c] = r;
9311 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9312 }
9313 else {
9314 if (!hash) hash = rb_hash_new();
9315 rb_hash_aset(hash, UINT2NUM(c), UINT2NUM(r));
9316 }
9317 }
9318 }
9319
9320 if (cr == ENC_CODERANGE_VALID && rb_enc_asciicompat(e1))
9321 cr = ENC_CODERANGE_7BIT;
9322 str_modify_keep_cr(str);
9323 s = (unsigned char *)RSTRING_PTR(str); send = (unsigned char *)RSTRING_END(str);
9324 termlen = rb_enc_mbminlen(enc);
9325 if (sflag) {
9326 int clen, tlen;
9327 long offset, max = RSTRING_LEN(str);
9328 unsigned int save = -1;
9329 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9330
9331 while (s < send) {
9332 int may_modify = 0;
9333
9334 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9335 if (!MBCLEN_CHARFOUND_P(r)) {
9336 SIZED_FREE_N(buf, max + termlen);
9337 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9338 }
9339 clen = MBCLEN_CHARFOUND_LEN(r);
9340 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9341
9342 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9343
9344 s += clen;
9345 if (c < 256) {
9346 c = trans[c];
9347 }
9348 else if (hash) {
9349 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9350 if (NIL_P(tmp)) {
9351 if (cflag) c = last;
9352 else c = errc;
9353 }
9354 else if (cflag) c = errc;
9355 else c = NUM2INT(tmp);
9356 }
9357 else {
9358 c = errc;
9359 }
9360 if (c != (unsigned int)-1) {
9361 if (save == c) {
9362 CHECK_IF_ASCII(c);
9363 continue;
9364 }
9365 save = c;
9366 tlen = rb_enc_codelen(c, enc);
9367 modify = 1;
9368 }
9369 else {
9370 save = -1;
9371 c = c0;
9372 if (enc != e1) may_modify = 1;
9373 }
9374 if ((offset = t - buf) + tlen > max) {
9375 size_t MAYBE_UNUSED(old) = max + termlen;
9376 max = offset + tlen + (send - s);
9377 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9378 t = buf + offset;
9379 }
9380 rb_enc_mbcput(c, t, enc);
9381 if (may_modify && memcmp(s, t, tlen) != 0) {
9382 modify = 1;
9383 }
9384 CHECK_IF_ASCII(c);
9385 t += tlen;
9386 }
9387 if (!STR_EMBED_P(str)) {
9388 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9389 }
9390 TERM_FILL((char *)t, termlen);
9391 RSTRING(str)->as.heap.ptr = (char *)buf;
9392 STR_SET_LEN(str, t - buf);
9393 STR_SET_NOEMBED(str);
9394 RSTRING(str)->as.heap.aux.capa = max;
9395 }
9396 else if (rb_enc_mbmaxlen(enc) == 1 || (singlebyte && !hash)) {
9397 while (s < send) {
9398 c = (unsigned char)*s;
9399 if (trans[c] != errc) {
9400 if (!cflag) {
9401 c = trans[c];
9402 *s = c;
9403 modify = 1;
9404 }
9405 else {
9406 *s = last;
9407 modify = 1;
9408 }
9409 }
9410 CHECK_IF_ASCII(c);
9411 s++;
9412 }
9413 }
9414 else {
9415 int clen, tlen;
9416 long offset, max = (long)((send - s) * 1.2);
9417 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9418
9419 while (s < send) {
9420 int may_modify = 0;
9421
9422 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9423 if (!MBCLEN_CHARFOUND_P(r)) {
9424 SIZED_FREE_N(buf, max + termlen);
9425 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9426 }
9427 clen = MBCLEN_CHARFOUND_LEN(r);
9428 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9429
9430 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9431
9432 if (c < 256) {
9433 c = trans[c];
9434 }
9435 else if (hash) {
9436 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9437 if (NIL_P(tmp)) {
9438 if (cflag) c = last;
9439 else c = errc;
9440 }
9441 else if (cflag) c = errc;
9442 else c = NUM2INT(tmp);
9443 }
9444 else {
9445 c = cflag ? last : errc;
9446 }
9447 if (c != errc) {
9448 tlen = rb_enc_codelen(c, enc);
9449 modify = 1;
9450 }
9451 else {
9452 c = c0;
9453 if (enc != e1) may_modify = 1;
9454 }
9455 if ((offset = t - buf) + tlen > max) {
9456 size_t MAYBE_UNUSED(old) = max + termlen;
9457 max = offset + tlen + (long)((send - s) * 1.2);
9458 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9459 t = buf + offset;
9460 }
9461
9462 rb_enc_mbcput(c, t, enc);
9463 if (may_modify && memcmp(s, t, tlen) != 0) {
9464 modify = 1;
9465 }
9466 CHECK_IF_ASCII(c);
9467 s += clen;
9468 t += tlen;
9469 }
9470 if (!STR_EMBED_P(str)) {
9471 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9472 }
9473 TERM_FILL((char *)t, termlen);
9474 RSTRING(str)->as.heap.ptr = (char *)buf;
9475 STR_SET_LEN(str, t - buf);
9476 STR_SET_NOEMBED(str);
9477 RSTRING(str)->as.heap.aux.capa = max;
9478 }
9479
9480 if (modify) {
9481 if (cr != ENC_CODERANGE_BROKEN)
9482 ENC_CODERANGE_SET(str, cr);
9483 rb_enc_associate(str, enc);
9484 return str;
9485 }
9486 return Qnil;
9487}
9488
9490 unsigned char *buf;
9491 unsigned char *ptr;
9492 size_t capa;
9493 size_t initial_capa;
9494};
9495
9496static inline void
9497tr_buffer_init(struct tr_buffer *buffer, size_t initial_capa)
9498{
9499 if (initial_capa < 32) {
9500 initial_capa = 32;
9501 }
9502 *buffer = (struct tr_buffer){ .initial_capa = initial_capa };
9503}
9504
9505static inline void
9506tr_buffer_ensure_capa(struct tr_buffer *buffer, size_t extra_capa)
9507{
9508 size_t offset = buffer->ptr - buffer->buf;
9509 size_t required_capa = offset + extra_capa;
9510 if (UNLIKELY(buffer->capa < required_capa)) {
9511 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9512 RUBY_ASSERT(new_capa >= 32); // Lower would cause infinite loop
9513 while (new_capa < required_capa) {
9514 new_capa = (size_t)(new_capa * 1.2);
9515 }
9516 SIZED_REALLOC_N(buffer->buf, unsigned char, new_capa, buffer->capa);
9517 buffer->ptr = buffer->buf + offset;
9518 buffer->capa = new_capa;
9519 }
9520}
9521
9522static inline void
9523tr_buffer_append(struct tr_buffer *buffer, const unsigned char *ptr, size_t len)
9524{
9525 if (len) {
9526 tr_buffer_ensure_capa(buffer, len);
9527 memcpy(buffer->ptr, ptr, len);
9528 buffer->ptr += len;
9529 }
9530}
9531
9532static inline void
9533tr_buffer_append_str(struct tr_buffer *buffer, VALUE str)
9534{
9535 tr_buffer_append(buffer, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9536}
9537
9538static inline void
9539tr_buffer_mbcput(struct tr_buffer *buffer, int codepoint, rb_encoding *enc)
9540{
9541 tr_buffer_ensure_capa(buffer, 4);
9542 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9543}
9544
9545static inline void
9546tr_buffer_free(struct tr_buffer *buffer)
9547{
9548 if (buffer->buf) {
9549 SIZED_FREE_N(buffer->buf, buffer->capa);
9550 }
9551}
9552
9553struct tr_pair {
9554 VALUE search;
9555 VALUE replace;
9556};
9557
9559 struct tr_pair *pairs;
9560 size_t index;
9561 rb_encoding *enc;
9562 int cr;
9563};
9564
9565static int
9566tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9567{
9568 struct tr_trans_pairs_coerce_args *args = (struct tr_trans_pairs_coerce_args *)_args;
9569 struct tr_pair *pair = &args->pairs[args->index];
9570 args->index++;
9571
9572 VALUE search = (VALUE)key;
9573 VALUE replace = (VALUE)value;
9574 StringValue(search);
9575 StringValue(replace);
9576
9577 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9578 rb_raise(rb_eArgError, "keys must be of size 1"); // TODO: better error message
9579 }
9580
9581 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9582 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9583
9584 pair->search = search;
9585 pair->replace = replace;
9586 return ST_CONTINUE;
9587}
9588
9589#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9590
9592 const unsigned char *s;
9593 const unsigned char *send;
9594
9595#ifdef HAVE_SIMD
9596 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9597 int needles_count;
9598#ifdef HAVE_SIMD_NEON
9599 uint64_t matches_bitmap;
9600#endif
9601#ifdef HAVE_SIMD_SSE2
9602 int matches_bitmap;
9603#endif
9604#endif
9605
9606 VALUE trans_table[256];
9607};
9608
9609static inline VALUE
9610tr_trans_pairs_search_basic(struct tr_trans_pairs_search *search)
9611{
9612 while (search->s < search->send) {
9613 VALUE repl = search->trans_table[*search->s];
9614 if (UNLIKELY(repl)) {
9615 return repl;
9616 }
9617
9618 search->s++;
9619 }
9620
9621 return 0;
9622}
9623
9624#ifdef HAVE_SIMD_SSE2
9625static inline VALUE
9626tr_trans_pairs_next_match_sse2(struct tr_trans_pairs_search *search)
9627{
9628 RUBY_ASSERT(search->matches_bitmap > 0);
9629 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9630
9631 RUBY_ASSERT(trailing_zeros < (sizeof(search->matches_bitmap) * CHAR_BIT));
9632 search->matches_bitmap >>= trailing_zeros;
9633 search->s += trailing_zeros;
9634
9635 RUBY_ASSERT(search->s <= search->send);
9636 return search->trans_table[*search->s];
9637}
9638
9639static inline VALUE
9640tr_trans_pairs_search_sse2(struct tr_trans_pairs_search *search)
9641{
9642 if (search->needles_count) {
9643 RBIMPL_ASSERT_OR_ASSUME(search->needles_count > 0);
9644 RBIMPL_ASSERT_OR_ASSUME(search->needles_count < TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9645
9646 if (search->matches_bitmap) {
9647 return tr_trans_pairs_next_match_sse2(search);
9648 }
9649
9650 if ((size_t)(search->send - search->s) >= sizeof(__m128i)) {
9651 int i;
9652 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9653 for (i = 0; i < search->needles_count; i++) {
9654 masks[i] = _mm_set1_epi8(search->needles[i]);
9655 }
9656
9657 do {
9658 const __m128i bytes = _mm_loadu_si128((__m128i const *)search->s);
9659
9660 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9661 for (i = 0; i < search->needles_count; i++) {
9662 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9663 }
9664
9665 for (i = 1; i < search->needles_count; i++) {
9666 matches[0] = _mm_or_si128(matches[0], matches[i]);
9667 }
9668
9669 const int bitmap = _mm_movemask_epi8(matches[0]);
9670
9671 if (bitmap) {
9672 search->matches_bitmap = bitmap;
9673 return tr_trans_pairs_next_match_sse2(search);
9674 }
9675 search->s += sizeof(__m128i);
9676 } while ((size_t)(search->send - search->s) >= sizeof(__m128i));
9677 }
9678 }
9679 return tr_trans_pairs_search_basic(search);
9680}
9681
9682#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9683#endif
9684
9685#ifdef HAVE_SIMD_NEON
9686static inline VALUE
9687tr_trans_pairs_next_match_neon(struct tr_trans_pairs_search *search)
9688{
9689 RUBY_ASSERT(search->matches_bitmap > 0);
9690 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9691
9692 // uint64_t >>= 64 would be undefined behaviour
9693 RUBY_ASSERT(trailing_zeros < (sizeof(search->matches_bitmap) * CHAR_BIT));
9694 search->matches_bitmap >>= trailing_zeros;
9695 search->s += trailing_zeros / 4;
9696
9697 RUBY_ASSERT(search->s <= search->send);
9698 return search->trans_table[*search->s];
9699}
9700
9701static inline VALUE
9702tr_trans_pairs_search_neon(struct tr_trans_pairs_search *search)
9703{
9704 if (search->needles_count) {
9705 RBIMPL_ASSERT_OR_ASSUME(search->needles_count > 0);
9706 RBIMPL_ASSERT_OR_ASSUME(search->needles_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9707
9708 if (search->matches_bitmap) {
9709 return tr_trans_pairs_next_match_neon(search);
9710 }
9711
9712 if ((size_t)(search->send - search->s) >= sizeof(uint8x16_t)) {
9713 int i;
9714 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9715 for (i = 0; i < search->needles_count; i++) {
9716 masks[i] = vdupq_n_u8(search->needles[i]);
9717 }
9718
9719 do {
9720 const uint8x16_t bytes = vld1q_u8(search->s);
9721
9722 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9723 for (i = 0; i < search->needles_count; i++) {
9724 matches[i] = vceqq_u8(bytes, masks[i]);
9725 }
9726
9727 for (i = 1; i < search->needles_count; i++) {
9728 matches[0] = vorrq_u8(matches[0], matches[i]);
9729 }
9730
9731 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9732 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9733
9734 if (bitmap) {
9735 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9736 return tr_trans_pairs_next_match_neon(search);
9737 }
9738 search->s += sizeof(uint8x16_t);
9739 } while ((size_t)(search->send - search->s) >= sizeof(uint8x16_t));
9740 }
9741 }
9742 return tr_trans_pairs_search_basic(search);
9743}
9744
9745#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9746#endif
9747
9748#ifndef tr_trans_pairs_search_impl
9749#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9750#endif
9751
9752static inline void
9753tr_trans_pairs_consume_match(struct tr_trans_pairs_search *search)
9754{
9755 search->s++;
9756#ifdef HAVE_SIMD
9757 search->matches_bitmap >>= 1;
9758#endif
9759}
9760
9761static VALUE
9762tr_trans_pairs(VALUE str, VALUE pairs_val)
9763{
9764 Check_Type(pairs_val, T_HASH);
9765 size_t pairs_count = RHASH_SIZE(pairs_val);
9766 mustnot_broken(str);
9767 rb_str_modify(str);
9768
9769 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0) return Qnil;
9770
9771 VALUE pairs_handle;
9772 struct tr_pair *pairs = ALLOCV_N(struct tr_pair, pairs_handle, pairs_count);
9773
9774 int cr = rb_enc_str_coderange(str);
9775 rb_encoding *enc = rb_str_enc_get(str);
9776
9777 struct tr_trans_pairs_coerce_args coerce_args = {
9778 .pairs = pairs,
9779 .enc = enc,
9780 .cr = cr,
9781 };
9782 rb_hash_foreach(pairs_val, tr_trans_pairs_coerce_i, (VALUE)&coerce_args);
9783 rb_encoding *e1 = coerce_args.enc;
9784
9785 VALUE hash = 0;
9786
9787 const unsigned char *sstart = (unsigned char *)RSTRING_PTR(str);
9788 long str_len = RSTRING_LEN(str);
9789 int termlen = rb_enc_mbminlen(e1);
9790
9791 struct tr_buffer buffer;
9792 tr_buffer_init(&buffer, str_len);
9793 bool modify = false;
9794
9795 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9796
9797 struct tr_trans_pairs_search search = {
9798 .s = sstart,
9799 .send = sstart + str_len,
9800 };
9801
9802 for (size_t index = 0; index < pairs_count; index++) {
9803 struct tr_pair *pair = &pairs[index];
9804
9805 char *ptr = RSTRING_PTR(pair->search);
9806 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr, RSTRING_END(pair->search), e1);
9807
9808 const unsigned char first_byte = (unsigned char)*ptr;
9809
9810#ifdef HAVE_SIMD
9811 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9812 search.needles[index] = first_byte;
9813 search.needles_count++;
9814 }
9815#endif
9816
9817 if (rb_enc_codelen(codepoint, e1) == 1) {
9818 search.trans_table[first_byte] = pair->replace;
9819 }
9820 else {
9821 search.trans_table[first_byte] = Qundef;
9822 if (!hash) {
9823 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9824 }
9825 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9826 }
9827 }
9828
9829 const unsigned char *checkpoint = search.s;
9830 VALUE repl;
9831 while ((repl = tr_trans_pairs_search_impl(&search))) {
9832 int clen = 1;
9833
9834 if (UNLIKELY(repl == Qundef)) {
9835 unsigned int c = rb_enc_mbc_to_codepoint((char *)search.s, (char *)search.send, e1);
9836 clen = rb_enc_codelen(c, e1);
9837 repl = rb_hash_lookup2(hash, UINT2NUM(c), 0);
9838 if (!repl) {
9839 tr_trans_pairs_consume_match(&search);
9840 continue;
9841 }
9842 }
9844
9845 modify = true;
9846
9847 if (checkpoint < search.s) {
9848 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9849 }
9850 tr_buffer_append_str(&buffer, repl);
9851 checkpoint = search.s + clen;
9852 tr_trans_pairs_consume_match(&search);
9853
9854 if (cr == ENC_CODERANGE_7BIT && rb_enc_str_coderange(repl) != ENC_CODERANGE_7BIT) {
9856 }
9857 }
9858
9859 if (modify && checkpoint < search.s) {
9860 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9861 }
9862 }
9863 else {
9864 const unsigned char *s = sstart;
9865 const unsigned char *send = sstart + str_len;
9866
9867 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9868
9869 for (size_t index = 0; index < pairs_count; index++) {
9870 struct tr_pair *pair = &pairs[index];
9871
9872 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search), RSTRING_END(pair->search), e1);
9873 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9874 }
9875
9876 while (s < send) {
9877 bool may_modify = false;
9878
9879 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9880 if (!MBCLEN_CHARFOUND_P(r)) {
9881 tr_buffer_free(&buffer);
9882 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9883 }
9884 int clen = MBCLEN_CHARFOUND_LEN(r);
9885 unsigned int c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9886 unsigned int c0 = c;
9887
9888 long tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
9889
9890 VALUE replacement = rb_hash_lookup(hash, UINT2NUM(c));
9891 if (NIL_P(replacement)) {
9892 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9893 c = c0;
9894 if (enc != e1) may_modify = true;
9895 }
9896 else {
9897 tlen = RSTRING_LEN(replacement);
9898 modify = true;
9899 }
9900
9901 if (NIL_P(replacement)) {
9902 tr_buffer_mbcput(&buffer, c, enc);
9903 }
9904 else {
9905 tr_buffer_append_str(&buffer, replacement);
9906 }
9907
9908 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
9909 modify = true;
9910 }
9911
9912 if (cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) {
9914 }
9915
9916 s += clen;
9917 }
9918 }
9919
9920 if (!modify) {
9921 return Qnil;
9922 }
9923
9924 if (!STR_EMBED_P(str)) {
9925 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9926 }
9927 tr_buffer_ensure_capa(&buffer, termlen);
9928 TERM_FILL((char *)buffer.ptr, termlen);
9929 RSTRING(str)->as.heap.ptr = (char *)buffer.buf;
9930 STR_SET_LEN(str, buffer.ptr - buffer.buf);
9931 STR_SET_NOEMBED(str);
9932 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
9933
9934 RB_GC_GUARD(hash);
9935
9936 if (cr != ENC_CODERANGE_BROKEN)
9937 ENC_CODERANGE_SET(str, cr);
9938 rb_enc_associate(str, e1);
9939 return str;
9940}
9941
9942/*
9943 * call-seq:
9944 * tr!(selector, replacements) -> self or nil
9945 * tr!(pairs) -> self or nil
9946 *
9947 * Like String#tr, except:
9948 *
9949 * - Performs substitutions in +self+ (not in a copy of +self+).
9950 * - Returns +self+ if any modifications were made, +nil+ otherwise.
9951 *
9952 * Related: {Modifying}[rdoc-ref:String@Modifying].
9953 */
9954
9955static VALUE
9956rb_str_tr_bang(int argc, VALUE *argv, VALUE str)
9957{
9958 rb_check_arity(argc, 1, 2);
9959
9960 if (argc == 1) {
9961 VALUE pairs = argv[0];
9962 return tr_trans_pairs(str, pairs);
9963 }
9964
9965 VALUE src = argv[0], repl = argv[1];
9966 return tr_trans(str, src, repl, 0);
9967}
9968
9969
9970/*
9971 * call-seq:
9972 * tr(selector, replacements) -> new_string
9973 * tr(pairs) -> new_string
9974 *
9975 * Accepts either a +selector+ and a +replacements+ string,
9976 * or a single +pairs+ Hash.
9977 *
9978 * When a +pairs+ Hash is provided the keys, returns a copy of +self+ with
9979 * the keys of the hash replaced by the values.
9980 *
9981 * - They keys must be strings containing a single codepoints.
9982 * - The values can be of any length.
9983 *
9984 * Example:
9985 *
9986 * 'hello'.tr('e' => 'er', 'l' => '', 'o' => 'o !') #=> "hero !"
9987 *
9988 * When +selector+ and +replacements+are provided, returns a copy of +self+
9989 * with each character specified by string +selector+ translated to the
9990 * corresponding character in string +replacements+.
9991 * The correspondence is _positional_:
9992 *
9993 * - Each occurrence of the first character specified by +selector+
9994 * is translated to the first character in +replacements+.
9995 * - Each occurrence of the second character specified by +selector+
9996 * is translated to the second character in +replacements+.
9997 * - And so on.
9998 *
9999 * Example:
10000 *
10001 * 'hello'.tr('el', 'ip') #=> "hippo"
10002 *
10003 * If +replacements+ is shorter than +selector+,
10004 * it is implicitly padded with its own last character:
10005 *
10006 * 'hello'.tr('aeiou', '-') # => "h-ll-"
10007 * 'hello'.tr('aeiou', 'AA-') # => "hAll-"
10008 *
10009 * Arguments +selector+ and +replacements+ must be valid character selectors
10010 * (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
10011 * and may use any of its valid forms, including negation, ranges, and escapes:
10012 *
10013 * 'hello'.tr('^aeiou', '-') # => "-e--o" # Negation.
10014 * 'ibm'.tr('b-z', 'a-z') # => "hal" # Range.
10015 * 'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret.
10016 * 'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen.
10017 * 'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash.
10018 *
10019 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10020 */
10021
10022static VALUE
10023rb_str_tr(int argc, VALUE *argv, VALUE str)
10024{
10025 rb_check_arity(argc, 1, 2);
10026
10027 str = str_duplicate(rb_cString, str);
10028
10029 if (argc == 1) {
10030 VALUE pairs = argv[0];
10031 VALUE result = tr_trans_pairs(str, pairs);
10032 if (NIL_P(result)) result = str;
10033 return str;
10034 }
10035
10036 VALUE src = argv[0], repl = argv[1];
10037 tr_trans(str, src, repl, 0);
10038 return str;
10039}
10040
10041#define TR_TABLE_MAX (UCHAR_MAX+1)
10042#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10043static void
10044tr_setup_table(VALUE str, char stable[TR_TABLE_SIZE], int first,
10045 VALUE *tablep, VALUE *ctablep, rb_encoding *enc)
10046{
10047 const unsigned int errc = -1;
10048 char buf[TR_TABLE_MAX];
10049 struct tr tr;
10050 unsigned int c;
10051 VALUE table = 0, ptable = 0;
10052 int i, l, cflag = 0;
10053
10054 tr.p = RSTRING_PTR(str); tr.pend = tr.p + RSTRING_LEN(str);
10055 tr.gen = tr.now = tr.max = 0;
10056
10057 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(tr.p, tr.pend, &l, enc) == '^') {
10058 cflag = 1;
10059 tr.p += l;
10060 }
10061 if (first) {
10062 for (i=0; i<TR_TABLE_MAX; i++) {
10063 stable[i] = 1;
10064 }
10065 stable[TR_TABLE_MAX] = cflag;
10066 }
10067 else if (stable[TR_TABLE_MAX] && !cflag) {
10068 stable[TR_TABLE_MAX] = 0;
10069 }
10070 for (i=0; i<TR_TABLE_MAX; i++) {
10071 buf[i] = cflag;
10072 }
10073
10074 while ((c = trnext(&tr, enc)) != errc) {
10075 if (c < TR_TABLE_MAX) {
10076 buf[(unsigned char)c] = !cflag;
10077 }
10078 else {
10079 VALUE key = UINT2NUM(c);
10080
10081 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10082 if (cflag) {
10083 ptable = *ctablep;
10084 table = ptable ? ptable : rb_hash_new();
10085 *ctablep = table;
10086 }
10087 else {
10088 table = rb_hash_new();
10089 ptable = *tablep;
10090 *tablep = table;
10091 }
10092 }
10093 if (table && (!ptable || (cflag ^ !NIL_P(rb_hash_aref(ptable, key))))) {
10094 rb_hash_aset(table, key, Qtrue);
10095 }
10096 }
10097 }
10098 for (i=0; i<TR_TABLE_MAX; i++) {
10099 stable[i] = stable[i] && buf[i];
10100 }
10101 if (!table && !cflag) {
10102 *tablep = 0;
10103 }
10104}
10105
10106
10107static int
10108tr_find(unsigned int c, const char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
10109{
10110 if (c < TR_TABLE_MAX) {
10111 return table[c] != 0;
10112 }
10113 else {
10114 VALUE v = UINT2NUM(c);
10115
10116 if (del) {
10117 if (!NIL_P(rb_hash_lookup(del, v)) &&
10118 (!nodel || NIL_P(rb_hash_lookup(nodel, v)))) {
10119 return TRUE;
10120 }
10121 }
10122 else if (nodel && !NIL_P(rb_hash_lookup(nodel, v))) {
10123 return FALSE;
10124 }
10125 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10126 }
10127}
10128
10129/*
10130 * call-seq:
10131 * delete!(*selectors) -> self or nil
10132 *
10133 * Like String#delete, but modifies +self+ in place;
10134 * returns +self+ if any characters were deleted, +nil+ otherwise.
10135 *
10136 * Related: see {Modifying}[rdoc-ref:String@Modifying].
10137 */
10138
10139static VALUE
10140rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
10141{
10142 char squeez[TR_TABLE_SIZE];
10143 rb_encoding *enc = 0;
10144 char *s, *send, *t;
10145 VALUE del = 0, nodel = 0;
10146 int modify = 0;
10147 int i, ascompat, cr;
10148
10149 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
10151 for (i=0; i<argc; i++) {
10152 VALUE s = argv[i];
10153
10154 StringValue(s);
10155 enc = rb_enc_check(str, s);
10156 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10157 }
10158
10159 str_modify_keep_cr(str);
10160 ascompat = rb_enc_asciicompat(enc);
10161 s = t = RSTRING_PTR(str);
10162 send = RSTRING_END(str);
10163 cr = ascompat ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
10164 while (s < send) {
10165 unsigned int c;
10166 int clen;
10167
10168 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
10169 if (squeez[c]) {
10170 modify = 1;
10171 }
10172 else {
10173 if (t != s) *t = c;
10174 t++;
10175 }
10176 s++;
10177 }
10178 else {
10179 c = rb_enc_codepoint_len(s, send, &clen, enc);
10180
10181 if (tr_find(c, squeez, del, nodel)) {
10182 modify = 1;
10183 }
10184 else {
10185 if (t != s) rb_enc_mbcput(c, t, enc);
10186 t += clen;
10188 }
10189 s += clen;
10190 }
10191 }
10192 TERM_FILL(t, TERM_LEN(str));
10193 STR_SET_LEN(str, t - RSTRING_PTR(str));
10194 ENC_CODERANGE_SET(str, cr);
10195
10196 if (modify) return str;
10197 return Qnil;
10198}
10199
10200
10201/*
10202 * call-seq:
10203 * delete(*selectors) -> new_string
10204 *
10205 * :include: doc/string/delete.rdoc
10206 *
10207 */
10208
10209static VALUE
10210rb_str_delete(int argc, VALUE *argv, VALUE str)
10211{
10212 str = str_duplicate(rb_cString, str);
10213 rb_str_delete_bang(argc, argv, str);
10214 return str;
10215}
10216
10217
10218/*
10219 * call-seq:
10220 * squeeze!(*selectors) -> self or nil
10221 *
10222 * Like String#squeeze, except that:
10223 *
10224 * - Characters are squeezed in +self+ (not in a copy of +self+).
10225 * - Returns +self+ if any changes are made, +nil+ otherwise.
10226 *
10227 * Related: See {Modifying}[rdoc-ref:String@Modifying].
10228 */
10229
10230static VALUE
10231rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
10232{
10233 char squeez[TR_TABLE_SIZE];
10234 rb_encoding *enc = 0;
10235 VALUE del = 0, nodel = 0;
10236 unsigned char *s, *send, *t;
10237 int i, modify = 0;
10238 int ascompat, singlebyte = single_byte_optimizable(str);
10239 unsigned int save;
10240
10241 if (argc == 0) {
10242 enc = STR_ENC_GET(str);
10243 }
10244 else {
10245 for (i=0; i<argc; i++) {
10246 VALUE s = argv[i];
10247
10248 StringValue(s);
10249 enc = rb_enc_check(str, s);
10250 if (singlebyte && !single_byte_optimizable(s))
10251 singlebyte = 0;
10252 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10253 }
10254 }
10255
10256 str_modify_keep_cr(str);
10257 s = t = (unsigned char *)RSTRING_PTR(str);
10258 if (!s || RSTRING_LEN(str) == 0) return Qnil;
10259 send = (unsigned char *)RSTRING_END(str);
10260 save = -1;
10261 ascompat = rb_enc_asciicompat(enc);
10262
10263 if (singlebyte) {
10264 while (s < send) {
10265 unsigned int c = *s++;
10266 if (c != save || (argc > 0 && !squeez[c])) {
10267 *t++ = save = c;
10268 }
10269 }
10270 }
10271 else {
10272 while (s < send) {
10273 unsigned int c;
10274 int clen;
10275
10276 if (ascompat && (c = *s) < 0x80) {
10277 if (c != save || (argc > 0 && !squeez[c])) {
10278 *t++ = save = c;
10279 }
10280 s++;
10281 }
10282 else {
10283 c = rb_enc_codepoint_len((char *)s, (char *)send, &clen, enc);
10284
10285 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10286 if (t != s) rb_enc_mbcput(c, t, enc);
10287 save = c;
10288 t += clen;
10289 }
10290 s += clen;
10291 }
10292 }
10293 }
10294
10295 TERM_FILL((char *)t, TERM_LEN(str));
10296 if ((char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10297 STR_SET_LEN(str, (char *)t - RSTRING_PTR(str));
10298 modify = 1;
10299 }
10300
10301 if (modify) return str;
10302 return Qnil;
10303}
10304
10305
10306/*
10307 * call-seq:
10308 * squeeze(*selectors) -> new_string
10309 *
10310 * :include: doc/string/squeeze.rdoc
10311 *
10312 */
10313
10314static VALUE
10315rb_str_squeeze(int argc, VALUE *argv, VALUE str)
10316{
10317 str = str_duplicate(rb_cString, str);
10318 rb_str_squeeze_bang(argc, argv, str);
10319 return str;
10320}
10321
10322
10323/*
10324 * call-seq:
10325 * tr_s!(selector, replacements) -> self or nil
10326 *
10327 * Like String#tr_s, except:
10328 *
10329 * - Modifies +self+ in place (not a copy of +self+).
10330 * - Returns +self+ if any changes were made, +nil+ otherwise.
10331 *
10332 * Related: {Modifying}[rdoc-ref:String@Modifying].
10333 */
10334
10335static VALUE
10336rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
10337{
10338 return tr_trans(str, src, repl, 1);
10339}
10340
10341
10342/*
10343 * call-seq:
10344 * tr_s(selector, replacements) -> new_string
10345 *
10346 * Like String#tr, except:
10347 *
10348 * - Also squeezes the modified portions of the translated string;
10349 * see String#squeeze.
10350 * - Returns the translated and squeezed string.
10351 *
10352 * Examples:
10353 *
10354 * 'hello'.tr_s('l', 'r') #=> "hero"
10355 * 'hello'.tr_s('el', '-') #=> "h-o"
10356 * 'hello'.tr_s('el', 'hx') #=> "hhxo"
10357 *
10358 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10359 *
10360 */
10361
10362static VALUE
10363rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
10364{
10365 str = str_duplicate(rb_cString, str);
10366 tr_trans(str, src, repl, 1);
10367 return str;
10368}
10369
10370
10371/*
10372 * call-seq:
10373 * count(*selectors) -> integer
10374 *
10375 * :include: doc/string/count.rdoc
10376 */
10377
10378static VALUE
10379rb_str_count(int argc, VALUE *argv, VALUE str)
10380{
10381 char table[TR_TABLE_SIZE];
10382 rb_encoding *enc = 0;
10383 VALUE del = 0, nodel = 0, tstr;
10384 const char *s, *send;
10385 int i;
10386 int ascompat;
10387 size_t n = 0;
10388
10390
10391 tstr = argv[0];
10392 StringValue(tstr);
10393 enc = rb_enc_check(str, tstr);
10394 if (argc == 1) {
10395 const char *ptstr;
10396 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10397 (ptstr = RSTRING_PTR(tstr),
10398 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
10399 !is_broken_string(str)) {
10400 int clen;
10401 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10402
10403 s = RSTRING_PTR(str);
10404 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10405 send = RSTRING_END(str);
10406 while (s < send) {
10407 if (*(unsigned char*)s++ == c) n++;
10408 }
10409 return SIZET2NUM(n);
10410 }
10411 }
10412
10413 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10414 for (i=1; i<argc; i++) {
10415 tstr = argv[i];
10416 StringValue(tstr);
10417 enc = rb_enc_check(str, tstr);
10418 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10419 }
10420
10421 s = RSTRING_PTR(str);
10422 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10423 send = RSTRING_END(str);
10424 ascompat = rb_enc_asciicompat(enc);
10425 while (s < send) {
10426 unsigned int c;
10427
10428 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
10429 if (table[c]) {
10430 n++;
10431 }
10432 s++;
10433 }
10434 else {
10435 int clen;
10436 c = rb_enc_codepoint_len(s, send, &clen, enc);
10437 if (tr_find(c, table, del, nodel)) {
10438 n++;
10439 }
10440 s += clen;
10441 }
10442 }
10443
10444 return SIZET2NUM(n);
10445}
10446
10447static VALUE
10448rb_fs_check(VALUE val)
10449{
10450 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING) && !RB_TYPE_P(val, T_REGEXP)) {
10451 val = rb_check_string_type(val);
10452 if (NIL_P(val)) return 0;
10453 }
10454 return val;
10455}
10456
10457static const char isspacetable[256] = {
10458 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10459 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10460 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10462 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10463 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10465 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10466 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10468 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10469 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10470 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10471 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10472 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10473 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10474};
10475
10476#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10477
10478static long
10479split_string(VALUE result, VALUE str, long beg, long len, long empty_count)
10480{
10481 if (empty_count >= 0 && len == 0) {
10482 return empty_count + 1;
10483 }
10484 if (empty_count > 0) {
10485 /* make different substrings */
10486 if (result) {
10487 do {
10488 rb_ary_push(result, str_new_empty_String(str));
10489 } while (--empty_count > 0);
10490 }
10491 else {
10492 do {
10493 rb_yield(str_new_empty_String(str));
10494 } while (--empty_count > 0);
10495 }
10496 }
10497 str = rb_str_subseq(str, beg, len);
10498 if (result) {
10499 rb_ary_push(result, str);
10500 }
10501 else {
10502 rb_yield(str);
10503 }
10504 return empty_count;
10505}
10506
10507typedef enum {
10508 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10509} split_type_t;
10510
10511static split_type_t
10512literal_split_pattern(VALUE spat, split_type_t default_type)
10513{
10514 rb_encoding *enc = STR_ENC_GET(spat);
10515 const char *ptr;
10516 long len;
10517 RSTRING_GETMEM(spat, ptr, len);
10518 if (len == 0) {
10519 /* Special case - split into chars */
10520 return SPLIT_TYPE_CHARS;
10521 }
10522 else if (rb_enc_asciicompat(enc)) {
10523 if (len == 1 && ptr[0] == ' ') {
10524 return SPLIT_TYPE_AWK;
10525 }
10526 }
10527 else {
10528 int l;
10529 if (rb_enc_ascget(ptr, ptr + len, &l, enc) == ' ' && len == l) {
10530 return SPLIT_TYPE_AWK;
10531 }
10532 }
10533 return default_type;
10534}
10535
10536/*
10537 * call-seq:
10538 * split(field_sep = $;, limit = 0) -> array_of_substrings
10539 * split(field_sep = $;, limit = 0) {|substring| ... } -> self
10540 *
10541 * :include: doc/string/split.rdoc
10542 *
10543 */
10544
10545static VALUE
10546rb_str_split_m(int argc, VALUE *argv, VALUE str)
10547{
10548 rb_encoding *enc;
10549 VALUE spat;
10550 VALUE limit;
10551 split_type_t split_type;
10552 long beg, end, i = 0, empty_count = -1;
10553 int lim = 0;
10554 VALUE result, tmp;
10555
10556 result = rb_block_given_p() ? Qfalse : Qnil;
10557 if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
10558 lim = NUM2INT(limit);
10559 if (lim <= 0) limit = Qnil;
10560 else if (lim == 1) {
10561 if (RSTRING_LEN(str) == 0)
10562 return result ? rb_ary_new2(0) : str;
10563 tmp = str_duplicate(rb_cString, str);
10564 if (!result) {
10565 rb_yield(tmp);
10566 return str;
10567 }
10568 return rb_ary_new3(1, tmp);
10569 }
10570 i = 1;
10571 }
10572 if (NIL_P(limit) && !lim) empty_count = 0;
10573
10574 enc = STR_ENC_GET(str);
10575 split_type = SPLIT_TYPE_REGEXP;
10576 if (!NIL_P(spat)) {
10577 spat = get_pat_quoted(spat, 0);
10578 }
10579 else if (NIL_P(spat = rb_fs)) {
10580 split_type = SPLIT_TYPE_AWK;
10581 }
10582 else if (!(spat = rb_fs_check(spat))) {
10583 rb_raise(rb_eTypeError, "value of $; must be String or Regexp");
10584 }
10585 else {
10586 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$; is set to non-nil value");
10587 }
10588 if (split_type != SPLIT_TYPE_AWK) {
10589 switch (BUILTIN_TYPE(spat)) {
10590 case T_REGEXP:
10591 rb_reg_options(spat); /* check if uninitialized */
10592 tmp = RREGEXP_SRC(spat);
10593 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10594 if (split_type == SPLIT_TYPE_AWK) {
10595 spat = tmp;
10596 split_type = SPLIT_TYPE_STRING;
10597 }
10598 break;
10599
10600 case T_STRING:
10601 mustnot_broken(spat);
10602 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10603 break;
10604
10605 default:
10607 }
10608 }
10609
10610#define SPLIT_STR(beg, len) ( \
10611 empty_count = split_string(result, str, beg, len, empty_count), \
10612 str_mod_check(str, str_start, str_len))
10613
10614 beg = 0;
10615 const char *ptr = RSTRING_PTR(str);
10616 const char *const str_start = ptr;
10617 const long str_len = RSTRING_LEN(str);
10618 const char *const eptr = str_start + str_len;
10619 if (split_type == SPLIT_TYPE_AWK) {
10620 const char *bptr = ptr;
10621 int skip = 1;
10622 unsigned int c;
10623
10624 if (result) result = rb_ary_new();
10625 end = beg;
10626 if (is_ascii_string(str)) {
10627 while (ptr < eptr) {
10628 c = (unsigned char)*ptr++;
10629 if (skip) {
10630 if (ascii_isspace(c)) {
10631 beg = ptr - bptr;
10632 }
10633 else {
10634 end = ptr - bptr;
10635 skip = 0;
10636 if (!NIL_P(limit) && lim <= i) break;
10637 }
10638 }
10639 else if (ascii_isspace(c)) {
10640 SPLIT_STR(beg, end-beg);
10641 skip = 1;
10642 beg = ptr - bptr;
10643 if (!NIL_P(limit)) ++i;
10644 }
10645 else {
10646 end = ptr - bptr;
10647 }
10648 }
10649 }
10650 else {
10651 while (ptr < eptr) {
10652 int n;
10653
10654 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10655 ptr += n;
10656 if (skip) {
10657 if (rb_isspace(c)) {
10658 beg = ptr - bptr;
10659 }
10660 else {
10661 end = ptr - bptr;
10662 skip = 0;
10663 if (!NIL_P(limit) && lim <= i) break;
10664 }
10665 }
10666 else if (rb_isspace(c)) {
10667 SPLIT_STR(beg, end-beg);
10668 skip = 1;
10669 beg = ptr - bptr;
10670 if (!NIL_P(limit)) ++i;
10671 }
10672 else {
10673 end = ptr - bptr;
10674 }
10675 }
10676 }
10677 }
10678 else if (split_type == SPLIT_TYPE_STRING) {
10679 const char *substr_start = ptr;
10680 const char *sptr = RSTRING_PTR(spat);
10681 long slen = RSTRING_LEN(spat);
10682
10683 if (result) result = rb_ary_new();
10684 mustnot_broken(str);
10685 enc = rb_enc_check(str, spat);
10686 while (ptr < eptr &&
10687 (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10688 /* Check we are at the start of a char */
10689 const char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc);
10690 if (t != ptr + end) {
10691 ptr = t;
10692 continue;
10693 }
10694 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10695 str_mod_check(spat, sptr, slen);
10696 ptr += end + slen;
10697 substr_start = ptr;
10698 if (!NIL_P(limit) && lim <= ++i) break;
10699 }
10700 beg = ptr - str_start;
10701 }
10702 else if (split_type == SPLIT_TYPE_CHARS) {
10703 int n;
10704
10705 if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
10706 mustnot_broken(str);
10707 enc = rb_enc_get(str);
10708 while (ptr < eptr &&
10709 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10710 SPLIT_STR(ptr - str_start, n);
10711 ptr += n;
10712 if (!NIL_P(limit) && lim <= ++i) break;
10713 }
10714 beg = ptr - str_start;
10715 }
10716 else {
10717 if (result) result = rb_ary_new();
10718 long len = RSTRING_LEN(str);
10719 long start = beg;
10720 int idx;
10721 int last_null = 0;
10722 VALUE match = 0;
10723
10724 for (; rb_reg_search(spat, str, start, 0) >= 0;
10725 (match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
10726 match = rb_backref_get();
10727 if (!result) rb_match_busy(match);
10728 end = RMATCH_BEG(match, 0);
10729 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10730 if (!ptr) {
10731 SPLIT_STR(0, 0);
10732 break;
10733 }
10734 else if (last_null == 1) {
10735 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10736 beg = start;
10737 }
10738 else {
10739 if (start == len)
10740 start++;
10741 else
10742 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10743 last_null = 1;
10744 continue;
10745 }
10746 }
10747 else {
10748 SPLIT_STR(beg, end-beg);
10749 beg = start = RMATCH_END(match, 0);
10750 }
10751 last_null = 0;
10752
10753 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10754 if (RMATCH_BEG(match, idx) == -1) continue;
10755 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10756 }
10757 if (!NIL_P(limit) && lim <= ++i) break;
10758 }
10759 if (match) rb_match_unbusy(match);
10760 }
10761 if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10762 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10763 }
10764
10765 return result ? result : str;
10766}
10767
10768VALUE
10769rb_str_split(VALUE str, const char *sep0)
10770{
10771 VALUE sep;
10772
10773 StringValue(str);
10774 sep = rb_str_new_cstr(sep0);
10775 return rb_str_split_m(1, &sep, str);
10776}
10777
10778#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10779
10780static inline int
10781enumerator_element(VALUE ary, VALUE e)
10782{
10783 if (ary) {
10784 rb_ary_push(ary, e);
10785 return 0;
10786 }
10787 else {
10788 rb_yield(e);
10789 return 1;
10790 }
10791}
10792
10793#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10794
10795static const char *
10796chomp_newline(const char *p, const char *e, rb_encoding *enc)
10797{
10798 const char *prev = rb_enc_prev_char(p, e, e, enc);
10799 if (rb_enc_is_newline(prev, e, enc)) {
10800 e = prev;
10801 prev = rb_enc_prev_char(p, e, e, enc);
10802 if (prev && rb_enc_ascget(prev, e, NULL, enc) == '\r')
10803 e = prev;
10804 }
10805 return e;
10806}
10807
10808static VALUE
10809get_rs(void)
10810{
10811 VALUE rs = rb_rs;
10812 if (!NIL_P(rs) &&
10813 (!RB_TYPE_P(rs, T_STRING) ||
10814 RSTRING_LEN(rs) != 1 ||
10815 RSTRING_PTR(rs)[0] != '\n')) {
10816 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$/ is set to non-default value");
10817 }
10818 return rs;
10819}
10820
10821#define rb_rs get_rs()
10822
10823static VALUE
10824rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
10825{
10826 rb_encoding *enc;
10827 VALUE line, rs, orig = str, opts = Qnil, chomp = Qfalse;
10828 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10829 long pos, rslen;
10830 int rsnewline = 0;
10831
10832 if (rb_scan_args(argc, argv, "01:", &rs, &opts) == 0)
10833 rs = rb_rs;
10834 if (!NIL_P(opts)) {
10835 static ID keywords[1];
10836 if (!keywords[0]) {
10837 keywords[0] = rb_intern_const("chomp");
10838 }
10839 rb_get_kwargs(opts, keywords, 0, 1, &chomp);
10840 chomp = (!UNDEF_P(chomp) && RTEST(chomp));
10841 }
10842
10843 if (NIL_P(rs)) {
10844 if (!ENUM_ELEM(ary, str)) {
10845 return ary;
10846 }
10847 else {
10848 return orig;
10849 }
10850 }
10851
10852 if (!RSTRING_LEN(str)) goto end;
10853 str = rb_str_new_frozen(str);
10854 const char *const ptr = subptr = RSTRING_PTR(str);
10855 const long len = RSTRING_LEN(str);
10856 pend = RSTRING_END(str);
10857 StringValue(rs);
10858 rslen = RSTRING_LEN(rs);
10859
10860 if (rs == rb_default_rs)
10861 enc = rb_enc_get(str);
10862 else
10863 enc = rb_enc_check(str, rs);
10864
10865 if (rslen == 0) {
10866 /* paragraph mode */
10867 int n;
10868 const char *eol = NULL;
10869 subend = subptr;
10870 while (subend < pend) {
10871 long chomp_rslen = 0;
10872 do {
10873 if (rb_enc_ascget(subend, pend, &n, enc) != '\r')
10874 n = 0;
10875 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
10876 if (rb_enc_is_newline(subend + n, pend, enc)) {
10877 if (eol == subend) break;
10878 subend += rslen;
10879 if (subptr) {
10880 eol = subend;
10881 chomp_rslen = -rslen;
10882 }
10883 }
10884 else {
10885 if (!subptr) subptr = subend;
10886 subend += rslen;
10887 }
10888 rslen = 0;
10889 } while (subend < pend);
10890 if (!subptr) break;
10891 if (rslen == 0) chomp_rslen = 0;
10892 line = rb_str_subseq(str, subptr - ptr,
10893 subend - subptr + (chomp ? chomp_rslen : rslen));
10894 if (ENUM_ELEM(ary, line)) {
10895 str_mod_check(str, ptr, len);
10896 }
10897 subptr = eol = NULL;
10898 }
10899 goto end;
10900 }
10901 else {
10902 rsptr = RSTRING_PTR(rs);
10903 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
10904 rb_enc_is_newline(rsptr, rsptr + RSTRING_LEN(rs), enc)) {
10905 rsnewline = 1;
10906 }
10907 }
10908
10909 if ((rs == rb_default_rs) && !rb_enc_asciicompat(enc)) {
10910 rs = rb_str_new(rsptr, rslen);
10911 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
10912 rsptr = RSTRING_PTR(rs);
10913 rslen = RSTRING_LEN(rs);
10914 }
10915
10916 while (subptr < pend) {
10917 pos = rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
10918 if (pos < 0) break;
10919 hit = subptr + pos;
10920 adjusted = rb_enc_right_char_head(subptr, hit, pend, enc);
10921 if (hit != adjusted) {
10922 subptr = adjusted;
10923 continue;
10924 }
10925 subend = hit += rslen;
10926 if (chomp) {
10927 if (rsnewline) {
10928 subend = chomp_newline(subptr, subend, enc);
10929 }
10930 else {
10931 subend -= rslen;
10932 }
10933 }
10934 line = rb_str_subseq(str, subptr - ptr, subend - subptr);
10935 if (ENUM_ELEM(ary, line)) {
10936 str_mod_check(str, ptr, len);
10937 }
10938 subptr = hit;
10939 }
10940
10941 if (subptr < pend) {
10942 if (chomp) {
10943 if (rsnewline) {
10944 pend = chomp_newline(subptr, pend, enc);
10945 }
10946 else if (pend - subptr >= rslen &&
10947 memcmp(pend - rslen, rsptr, rslen) == 0) {
10948 pend -= rslen;
10949 }
10950 }
10951 line = rb_str_subseq(str, subptr - ptr, pend - subptr);
10952 ENUM_ELEM(ary, line);
10953 RB_GC_GUARD(str);
10954 }
10955
10956 end:
10957 if (ary)
10958 return ary;
10959 else
10960 return orig;
10961}
10962
10963/*
10964 * call-seq:
10965 * each_line(record_separator = $/, chomp: false) {|substring| ... } -> self
10966 * each_line(record_separator = $/, chomp: false) -> enumerator
10967 *
10968 * :include: doc/string/each_line.rdoc
10969 *
10970 */
10971
10972static VALUE
10973rb_str_each_line(int argc, VALUE *argv, VALUE str)
10974{
10975 RETURN_SIZED_ENUMERATOR(str, argc, argv, 0);
10976 return rb_str_enumerate_lines(argc, argv, str, 0);
10977}
10978
10979/*
10980 * call-seq:
10981 * lines(record_separator = $/, chomp: false) -> array_of_strings
10982 *
10983 * Returns substrings ("lines") of +self+
10984 * according to the given arguments:
10985 *
10986 * s = <<~EOT
10987 * This is the first line.
10988 * This is line two.
10989 *
10990 * This is line four.
10991 * This is line five.
10992 * EOT
10993 *
10994 * With the default argument values:
10995 *
10996 * $/ # => "\n"
10997 * s.lines
10998 * # =>
10999 * ["This is the first line.\n",
11000 * "This is line two.\n",
11001 * "\n",
11002 * "This is line four.\n",
11003 * "This is line five.\n"]
11004 *
11005 * With a different +record_separator+:
11006 *
11007 * record_separator = ' is '
11008 * s.lines(record_separator)
11009 * # =>
11010 * ["This is ",
11011 * "the first line.\nThis is ",
11012 * "line two.\n\nThis is ",
11013 * "line four.\nThis is ",
11014 * "line five.\n"]
11015 *
11016 * With keyword argument +chomp+ as +true+,
11017 * removes the trailing newline from each line:
11018 *
11019 * s.lines(chomp: true)
11020 * # =>
11021 * ["This is the first line.",
11022 * "This is line two.",
11023 * "",
11024 * "This is line four.",
11025 * "This is line five."]
11026 *
11027 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
11028 */
11029
11030static VALUE
11031rb_str_lines(int argc, VALUE *argv, VALUE str)
11032{
11033 VALUE ary = WANTARRAY("lines", 0);
11034 return rb_str_enumerate_lines(argc, argv, str, ary);
11035}
11036
11037static VALUE
11038rb_str_each_byte_size(VALUE str, VALUE args, VALUE eobj)
11039{
11040 return LONG2FIX(RSTRING_LEN(str));
11041}
11042
11043static VALUE
11044rb_str_enumerate_bytes(VALUE str, VALUE ary)
11045{
11046 long i;
11047
11048 for (i=0; i<RSTRING_LEN(str); i++) {
11049 ENUM_ELEM(ary, INT2FIX((unsigned char)RSTRING_PTR(str)[i]));
11050 }
11051 if (ary)
11052 return ary;
11053 else
11054 return str;
11055}
11056
11057/*
11058 * call-seq:
11059 * each_byte {|byte| ... } -> self
11060 * each_byte -> enumerator
11061 *
11062 * :include: doc/string/each_byte.rdoc
11063 *
11064 */
11065
11066static VALUE
11067rb_str_each_byte(VALUE str)
11068{
11069 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_byte_size);
11070 return rb_str_enumerate_bytes(str, 0);
11071}
11072
11073/*
11074 * call-seq:
11075 * bytes -> array_of_bytes
11076 *
11077 * :include: doc/string/bytes.rdoc
11078 *
11079 */
11080
11081static VALUE
11082rb_str_bytes(VALUE str)
11083{
11084 VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
11085 return rb_str_enumerate_bytes(str, ary);
11086}
11087
11088static VALUE
11089rb_str_each_char_size(VALUE str, VALUE args, VALUE eobj)
11090{
11091 return rb_str_length(str);
11092}
11093
11094static VALUE
11095rb_str_enumerate_chars(VALUE str, VALUE ary)
11096{
11097 VALUE orig = str;
11098 long i, len, n;
11099 const char *ptr;
11100 rb_encoding *enc;
11101
11102 str = rb_str_new_frozen(str);
11103 ptr = RSTRING_PTR(str);
11104 len = RSTRING_LEN(str);
11105 enc = rb_enc_get(str);
11106
11108 for (i = 0; i < len; i += n) {
11109 n = rb_enc_fast_mbclen(ptr + i, ptr + len, enc);
11110 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
11111 }
11112 }
11113 else {
11114 for (i = 0; i < len; i += n) {
11115 n = rb_enc_mbclen(ptr + i, ptr + len, enc);
11116 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
11117 }
11118 }
11119 RB_GC_GUARD(str);
11120 if (ary)
11121 return ary;
11122 else
11123 return orig;
11124}
11125
11126/*
11127 * call-seq:
11128 * each_char {|char| ... } -> self
11129 * each_char -> enumerator
11130 *
11131 * :include: doc/string/each_char.rdoc
11132 *
11133 */
11134
11135static VALUE
11136rb_str_each_char(VALUE str)
11137{
11138 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
11139 return rb_str_enumerate_chars(str, 0);
11140}
11141
11142/*
11143 * call-seq:
11144 * chars -> array_of_characters
11145 *
11146 * :include: doc/string/chars.rdoc
11147 *
11148 */
11149
11150static VALUE
11151rb_str_chars(VALUE str)
11152{
11153 VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
11154 return rb_str_enumerate_chars(str, ary);
11155}
11156
11157static VALUE
11158rb_str_enumerate_codepoints(VALUE str, VALUE ary)
11159{
11160 VALUE orig = str;
11161 int n;
11162 unsigned int c;
11163 const char *ptr, *end;
11164 rb_encoding *enc;
11165 int enc_asciicompat;
11166
11167 if (single_byte_optimizable(str))
11168 return rb_str_enumerate_bytes(str, ary);
11169
11170 str = rb_str_new_frozen(str);
11171 ptr = RSTRING_PTR(str);
11172 end = RSTRING_END(str);
11173 enc = STR_ENC_GET(str);
11174 enc_asciicompat = rb_enc_asciicompat(enc);
11175
11176 while (ptr < end) {
11177 /* Fast path: ASCII byte in an ASCII-compatible encoding is its own codepoint;
11178 * skip rb_enc_codepoint_len and return the byte directly.
11179 */
11180 n = 1;
11181 c = (enc_asciicompat && ISASCII(*ptr)) ?
11182 (unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11183 ENUM_ELEM(ary, UINT2NUM(c));
11184 ptr += n;
11185 }
11186 RB_GC_GUARD(str);
11187 if (ary)
11188 return ary;
11189 else
11190 return orig;
11191}
11192
11193/*
11194 * call-seq:
11195 * each_codepoint {|codepoint| ... } -> self
11196 * each_codepoint -> enumerator
11197 *
11198 * :include: doc/string/each_codepoint.rdoc
11199 *
11200 */
11201
11202static VALUE
11203rb_str_each_codepoint(VALUE str)
11204{
11205 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
11206 return rb_str_enumerate_codepoints(str, 0);
11207}
11208
11209/*
11210 * call-seq:
11211 * codepoints -> array_of_integers
11212 *
11213 * :include: doc/string/codepoints.rdoc
11214 *
11215 */
11216
11217static VALUE
11218rb_str_codepoints(VALUE str)
11219{
11220 VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
11221 return rb_str_enumerate_codepoints(str, ary);
11222}
11223
11224static regex_t *
11225get_reg_grapheme_cluster(rb_encoding *enc)
11226{
11227 int encidx = rb_enc_to_index(enc);
11228
11229 const OnigUChar source_ascii[] = "\\X";
11230 const OnigUChar *source = source_ascii;
11231 size_t source_len = sizeof(source_ascii) - 1;
11232
11233 switch (encidx) {
11234#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11235#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11236#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11237#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11238#define CASE_UTF(e) \
11239 case ENCINDEX_UTF_##e: { \
11240 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11241 source = source_UTF_##e; \
11242 source_len = sizeof(source_UTF_##e); \
11243 break; \
11244 }
11245 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11246#undef CASE_UTF
11247#undef CHARS_16BE
11248#undef CHARS_16LE
11249#undef CHARS_32BE
11250#undef CHARS_32LE
11251 }
11252
11253 regex_t *reg_grapheme_cluster;
11254 OnigErrorInfo einfo;
11255 int r = onig_new(&reg_grapheme_cluster, source, source + source_len,
11256 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11257 if (r) {
11258 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11259 onig_error_code_to_str(message, r, &einfo);
11260 rb_fatal("cannot compile grapheme cluster regexp: %s", (char *)message);
11261 }
11262
11263 return reg_grapheme_cluster;
11264}
11265
11266static regex_t *
11267get_cached_reg_grapheme_cluster(rb_encoding *enc)
11268{
11269 int encidx = rb_enc_to_index(enc);
11270 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11271
11272 if (encidx == rb_utf8_encindex()) {
11273 if (!reg_grapheme_cluster_utf8) {
11274 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11275 }
11276
11277 return reg_grapheme_cluster_utf8;
11278 }
11279
11280 return NULL;
11281}
11282
11283static VALUE
11284rb_str_each_grapheme_cluster_size(VALUE str, VALUE args, VALUE eobj)
11285{
11286 size_t grapheme_cluster_count = 0;
11287 rb_encoding *enc = get_encoding(str);
11288 const char *ptr, *end;
11289
11290 if (!rb_enc_unicode_p(enc)) {
11291 return rb_str_length(str);
11292 }
11293
11294 bool cached_reg_grapheme_cluster = true;
11295 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11296 if (!reg_grapheme_cluster) {
11297 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11298 cached_reg_grapheme_cluster = false;
11299 }
11300
11301 ptr = RSTRING_PTR(str);
11302 end = RSTRING_END(str);
11303
11304 while (ptr < end) {
11305 OnigPosition len = onig_match(reg_grapheme_cluster,
11306 (const OnigUChar *)ptr, (const OnigUChar *)end,
11307 (const OnigUChar *)ptr, NULL, 0);
11308 if (len <= 0) break;
11309 grapheme_cluster_count++;
11310 ptr += len;
11311 }
11312
11313 if (!cached_reg_grapheme_cluster) {
11314 onig_free(reg_grapheme_cluster);
11315 }
11316
11317 return SIZET2NUM(grapheme_cluster_count);
11318}
11319
11320static VALUE
11321rb_str_enumerate_grapheme_clusters(VALUE str, VALUE ary)
11322{
11323 VALUE orig = str;
11324 rb_encoding *enc = get_encoding(str);
11325 const char *ptr0, *ptr, *end;
11326
11327 if (!rb_enc_unicode_p(enc)) {
11328 return rb_str_enumerate_chars(str, ary);
11329 }
11330
11331 if (!ary) str = rb_str_new_frozen(str);
11332
11333 bool cached_reg_grapheme_cluster = true;
11334 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11335 if (!reg_grapheme_cluster) {
11336 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11337 cached_reg_grapheme_cluster = false;
11338 }
11339
11340 ptr0 = ptr = RSTRING_PTR(str);
11341 end = RSTRING_END(str);
11342
11343 while (ptr < end) {
11344 OnigPosition len = onig_match(reg_grapheme_cluster,
11345 (const OnigUChar *)ptr, (const OnigUChar *)end,
11346 (const OnigUChar *)ptr, NULL, 0);
11347 if (len <= 0) break;
11348 ENUM_ELEM(ary, rb_str_subseq(str, ptr-ptr0, len));
11349 ptr += len;
11350 }
11351
11352 if (!cached_reg_grapheme_cluster) {
11353 onig_free(reg_grapheme_cluster);
11354 }
11355
11356 RB_GC_GUARD(str);
11357 if (ary)
11358 return ary;
11359 else
11360 return orig;
11361}
11362
11363/*
11364 * call-seq:
11365 * each_grapheme_cluster {|grapheme_cluster| ... } -> self
11366 * each_grapheme_cluster -> enumerator
11367 *
11368 * :include: doc/string/each_grapheme_cluster.rdoc
11369 *
11370 */
11371
11372static VALUE
11373rb_str_each_grapheme_cluster(VALUE str)
11374{
11375 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_grapheme_cluster_size);
11376 return rb_str_enumerate_grapheme_clusters(str, 0);
11377}
11378
11379/*
11380 * call-seq:
11381 * grapheme_clusters -> array_of_grapheme_clusters
11382 *
11383 * :include: doc/string/grapheme_clusters.rdoc
11384 *
11385 */
11386
11387static VALUE
11388rb_str_grapheme_clusters(VALUE str)
11389{
11390 VALUE ary = WANTARRAY("grapheme_clusters", rb_str_strlen(str));
11391 return rb_str_enumerate_grapheme_clusters(str, ary);
11392}
11393
11394static long
11395chopped_length(VALUE str)
11396{
11397 rb_encoding *enc = STR_ENC_GET(str);
11398 const char *p, *p2, *beg, *end;
11399
11400 beg = RSTRING_PTR(str);
11401 end = beg + RSTRING_LEN(str);
11402 if (beg >= end) return 0;
11403 p = rb_enc_prev_char(beg, end, end, enc);
11404 if (!p) return 0;
11405 if (p > beg && rb_enc_ascget(p, end, 0, enc) == '\n') {
11406 p2 = rb_enc_prev_char(beg, p, end, enc);
11407 if (p2 && rb_enc_ascget(p2, end, 0, enc) == '\r') p = p2;
11408 }
11409 return p - beg;
11410}
11411
11412/*
11413 * call-seq:
11414 * chop! -> self or nil
11415 *
11416 * Like String#chop, except that:
11417 *
11418 * - Removes trailing characters from +self+ (not from a copy of +self+).
11419 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11420 *
11421 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11422 */
11423
11424static VALUE
11425rb_str_chop_bang(VALUE str)
11426{
11427 str_modify_keep_cr(str);
11428 if (RSTRING_LEN(str) > 0) {
11429 long len;
11430 len = chopped_length(str);
11431 STR_SET_LEN(str, len);
11432 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11433 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11435 }
11436 return str;
11437 }
11438 return Qnil;
11439}
11440
11441
11442/*
11443 * call-seq:
11444 * chop -> new_string
11445 *
11446 * :include: doc/string/chop.rdoc
11447 *
11448 */
11449
11450static VALUE
11451rb_str_chop(VALUE str)
11452{
11453 return rb_str_subseq(str, 0, chopped_length(str));
11454}
11455
11456static long
11457smart_chomp(VALUE str, const char *e, const char *p)
11458{
11459 rb_encoding *enc = rb_enc_get(str);
11460 if (rb_enc_mbminlen(enc) > 1) {
11461 /* a receiver shorter than one character has nothing to chomp */
11462 if (e - p < rb_enc_mbminlen(enc)) return e - p;
11463 const char *pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11464 if (rb_enc_is_newline(pp, e, enc)) {
11465 e = pp;
11466 }
11467 pp = e - rb_enc_mbminlen(enc);
11468 if (pp >= p) {
11469 pp = rb_enc_left_char_head(p, pp, e, enc);
11470 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11471 e = pp;
11472 }
11473 }
11474 }
11475 else {
11476 switch (*(e-1)) { /* not e[-1] to get rid of VC bug */
11477 case '\n':
11478 if (--e > p && *(e-1) == '\r') {
11479 --e;
11480 }
11481 break;
11482 case '\r':
11483 --e;
11484 break;
11485 }
11486 }
11487 return e - p;
11488}
11489
11490static long
11491chompped_length(VALUE str, VALUE rs)
11492{
11493 rb_encoding *enc;
11494 int newline;
11495 const char *pp, *e, *rsptr;
11496 long rslen;
11497 const char *const p = RSTRING_PTR(str);
11498 long len = RSTRING_LEN(str);
11499
11500 if (len == 0) return 0;
11501 e = p + len;
11502 if (rs == rb_default_rs) {
11503 return smart_chomp(str, e, p);
11504 }
11505
11506 enc = rb_enc_get(str);
11507 RSTRING_GETMEM(rs, rsptr, rslen);
11508 if (rslen == 0) {
11509 if (rb_enc_mbminlen(enc) > 1) {
11510 while (e - p >= rb_enc_mbminlen(enc)) {
11511 pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11512 if (!rb_enc_is_newline(pp, e, enc)) break;
11513 e = pp;
11514 pp -= rb_enc_mbminlen(enc);
11515 if (pp >= p) {
11516 pp = rb_enc_left_char_head(p, pp, e, enc);
11517 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11518 e = pp;
11519 }
11520 }
11521 }
11522 }
11523 else {
11524 while (e > p && *(e-1) == '\n') {
11525 --e;
11526 if (e > p && *(e-1) == '\r')
11527 --e;
11528 }
11529 }
11530 return e - p;
11531 }
11532 if (rslen > len) return len;
11533
11534 enc = rb_enc_get(rs);
11535 newline = rsptr[rslen-1];
11536 if (rslen == rb_enc_mbminlen(enc)) {
11537 if (rslen == 1) {
11538 if (newline == '\n')
11539 return smart_chomp(str, e, p);
11540 }
11541 else {
11542 if (rb_enc_is_newline(rsptr, rsptr+rslen, enc))
11543 return smart_chomp(str, e, p);
11544 }
11545 }
11546
11547 enc = rb_enc_check(str, rs);
11548 if (is_broken_string(rs)) {
11549 return len;
11550 }
11551 pp = e - rslen;
11552 if (p[len-1] == newline &&
11553 (rslen <= 1 ||
11554 memcmp(rsptr, pp, rslen) == 0)) {
11555 if (at_char_boundary(p, pp, e, enc))
11556 return len - rslen;
11557 RB_GC_GUARD(rs);
11558 }
11559 return len;
11560}
11561
11567static VALUE
11568chomp_rs(int argc, const VALUE *argv)
11569{
11570 rb_check_arity(argc, 0, 1);
11571 if (argc > 0) {
11572 VALUE rs = argv[0];
11573 if (!NIL_P(rs)) StringValue(rs);
11574 return rs;
11575 }
11576 else {
11577 return rb_rs;
11578 }
11579}
11580
11581static VALUE
11582str_shrink(VALUE str, long len)
11583{
11584 str_modify_keep_cr(str);
11585 STR_SET_LEN(str, len);
11586 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11587 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11589 }
11590 return str;
11591}
11592
11593VALUE
11594rb_str_chomp_string(VALUE str, VALUE rs)
11595{
11596 long olen = RSTRING_LEN(str);
11597 long len = chompped_length(str, rs);
11598 if (len >= olen) return Qnil;
11599 return str_shrink(str, len);
11600}
11601
11602/*
11603 * call-seq:
11604 * chomp!(line_sep = $/) -> self or nil
11605 *
11606 * Like String#chomp, except that:
11607 *
11608 * - Removes trailing characters from +self+ (not from a copy of +self+).
11609 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11610 *
11611 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11612 */
11613
11614static VALUE
11615rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
11616{
11617 VALUE rs;
11618 str_modifiable(str);
11619 if (RSTRING_LEN(str) == 0 && argc < 2) return Qnil;
11620 rs = chomp_rs(argc, argv);
11621 if (NIL_P(rs)) return Qnil;
11622 return rb_str_chomp_string(str, rs);
11623}
11624
11625
11626/*
11627 * call-seq:
11628 * chomp(line_sep = $/) -> new_string
11629 *
11630 * :include: doc/string/chomp.rdoc
11631 *
11632 */
11633
11634static VALUE
11635rb_str_chomp(int argc, VALUE *argv, VALUE str)
11636{
11637 VALUE rs = chomp_rs(argc, argv);
11638 if (NIL_P(rs)) return str_duplicate(rb_cString, str);
11639 return rb_str_subseq(str, 0, chompped_length(str, rs));
11640}
11641
11642static void
11643tr_setup_table_multi(char table[TR_TABLE_SIZE], VALUE *tablep, VALUE *ctablep,
11644 VALUE str, int num_selectors, VALUE *selectors)
11645{
11646 int i;
11647
11648 for (i=0; i<num_selectors; i++) {
11649 VALUE selector = selectors[i];
11650 rb_encoding *enc;
11651
11652 StringValue(selector);
11653 enc = rb_enc_check(str, selector);
11654 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11655 }
11656}
11657
11658static long
11659lstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11660{
11661 const char *const start = s;
11662
11663 if (!s || s >= e) return 0;
11664
11665 /* remove spaces at head */
11666 if (single_byte_optimizable(str)) {
11667 while (s < e && (*s == '\0' || ascii_isspace(*s))) s++;
11668 }
11669 else {
11670 while (s < e) {
11671 int n;
11672 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11673
11674 if (cc && !rb_isspace(cc)) break;
11675 s += n;
11676 }
11677 }
11678 return s - start;
11679}
11680
11681static long
11682lstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11683 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11684{
11685 const char *const start = s;
11686
11687 if (!s || s >= e) return 0;
11688
11689 /* remove leading characters in the table */
11690 while (s < e) {
11691 int n;
11692 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11693
11694 if (!tr_find(cc, table, del, nodel)) break;
11695 s += n;
11696 }
11697 return s - start;
11698}
11699
11700/*
11701 * call-seq:
11702 * lstrip!(*selectors) -> self or nil
11703 *
11704 * Like String#lstrip, except that:
11705 *
11706 * - Performs stripping in +self+ (not in a copy of +self+).
11707 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11708 *
11709 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11710 */
11711
11712static VALUE
11713rb_str_lstrip_bang(int argc, VALUE *argv, VALUE str)
11714{
11715 rb_encoding *enc;
11716 char *start;
11717 long olen, loffset;
11718
11719 str_modify_keep_cr(str);
11720 enc = STR_ENC_GET(str);
11721 RSTRING_GETMEM(str, start, olen);
11722 if (argc > 0) {
11723 char table[TR_TABLE_SIZE];
11724 VALUE del = 0, nodel = 0;
11725
11726 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11727 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11728 }
11729 else {
11730 loffset = lstrip_offset(str, start, start+olen, enc);
11731 }
11732
11733 if (loffset > 0) {
11734 long len = olen-loffset;
11735 memmove(start, start + loffset, len);
11736 STR_SET_LEN(str, len);
11737 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11738 return str;
11739 }
11740 return Qnil;
11741}
11742
11743
11744/*
11745 * call-seq:
11746 * lstrip(*selectors) -> new_string
11747 *
11748 * Returns a copy of +self+ with leading whitespace removed;
11749 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11750 *
11751 * whitespace = "\x00\t\n\v\f\r "
11752 * s = whitespace + 'abc' + whitespace
11753 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11754 * s.lstrip
11755 * # => "abc\u0000\t\n\v\f\r "
11756 *
11757 * If +selectors+ are given, removes characters of +selectors+ from the beginning of +self+:
11758 *
11759 * s = "---abc+++"
11760 * s.lstrip("-") # => "abc+++"
11761 *
11762 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11763 * and may use any of its valid forms, including negation, ranges, and escapes:
11764 *
11765 * "01234abc56789".lstrip("0-9") # "abc56789"
11766 * "01234abc56789".lstrip("0-9", "^4-6") # "4abc56789"
11767 *
11768 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11769 */
11770
11771static VALUE
11772rb_str_lstrip(int argc, VALUE *argv, VALUE str)
11773{
11774 const char *start;
11775 long len, loffset;
11776
11777 RSTRING_GETMEM(str, start, len);
11778 if (argc > 0) {
11779 char table[TR_TABLE_SIZE];
11780 VALUE del = 0, nodel = 0;
11781
11782 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11783 loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel);
11784 }
11785 else {
11786 loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
11787 }
11788 if (loffset <= 0) return str_duplicate(rb_cString, str);
11789 return rb_str_subseq(str, loffset, len - loffset);
11790}
11791
11792static long
11793rstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11794{
11795 const char *t;
11796
11797 rb_str_check_dummy_enc(enc);
11798 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11799 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11800 }
11801 if (!s || s >= e) return 0;
11802 t = e;
11803
11804 /* remove trailing spaces or '\0's */
11805 if (single_byte_optimizable(str)) {
11806 unsigned char c;
11807 while (s < t && ((c = *(t-1)) == '\0' || ascii_isspace(c))) t--;
11808 }
11809 else {
11810 const char *tp;
11811
11812 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11813 unsigned int c = rb_enc_codepoint(tp, e, enc);
11814 if (c && !rb_isspace(c)) break;
11815 t = tp;
11816 }
11817 }
11818 return e - t;
11819}
11820
11821static long
11822rstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11823 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11824{
11825 const char *t, *tp;
11826
11827 rb_str_check_dummy_enc(enc);
11828 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11829 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11830 }
11831 if (!s || s >= e) return 0;
11832 t = e;
11833
11834 /* remove trailing characters in the table */
11835 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11836 unsigned int c = rb_enc_codepoint(tp, e, enc);
11837 if (!tr_find(c, table, del, nodel)) break;
11838 t = tp;
11839 }
11840
11841 return e - t;
11842}
11843
11844/*
11845 * call-seq:
11846 * rstrip!(*selectors) -> self or nil
11847 *
11848 * Like String#rstrip, except that:
11849 *
11850 * - Performs stripping in +self+ (not in a copy of +self+).
11851 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11852 *
11853 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11854 */
11855
11856static VALUE
11857rb_str_rstrip_bang(int argc, VALUE *argv, VALUE str)
11858{
11859 rb_encoding *enc;
11860 char *start;
11861 long olen, roffset;
11862
11863 str_modify_keep_cr(str);
11864 enc = STR_ENC_GET(str);
11865 RSTRING_GETMEM(str, start, olen);
11866 if (argc > 0) {
11867 char table[TR_TABLE_SIZE];
11868 VALUE del = 0, nodel = 0;
11869
11870 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11871 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11872 }
11873 else {
11874 roffset = rstrip_offset(str, start, start+olen, enc);
11875 }
11876 if (roffset > 0) {
11877 long len = olen - roffset;
11878
11879 STR_SET_LEN(str, len);
11880 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11881 return str;
11882 }
11883 return Qnil;
11884}
11885
11886
11887/*
11888 * call-seq:
11889 * rstrip(*selectors) -> new_string
11890 *
11891 * Returns a copy of +self+ with trailing whitespace removed;
11892 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11893 *
11894 * whitespace = "\x00\t\n\v\f\r "
11895 * s = whitespace + 'abc' + whitespace
11896 * s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11897 * s.rstrip # => "\u0000\t\n\v\f\r abc"
11898 *
11899 * If +selectors+ are given, removes characters of +selectors+ from the end of +self+:
11900 *
11901 * s = "---abc+++"
11902 * s.rstrip("+") # => "---abc"
11903 *
11904 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11905 * and may use any of its valid forms, including negation, ranges, and escapes:
11906 *
11907 * "01234abc56789".rstrip("0-9") # "01234abc"
11908 * "01234abc56789".rstrip("0-9", "^4-6") # "01234abc56"
11909 *
11910 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11911 */
11912
11913static VALUE
11914rb_str_rstrip(int argc, VALUE *argv, VALUE str)
11915{
11916 rb_encoding *enc;
11917 const char *start;
11918 long olen, roffset;
11919
11920 enc = STR_ENC_GET(str);
11921 RSTRING_GETMEM(str, start, olen);
11922 if (argc > 0) {
11923 char table[TR_TABLE_SIZE];
11924 VALUE del = 0, nodel = 0;
11925
11926 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11927 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11928 }
11929 else {
11930 roffset = rstrip_offset(str, start, start+olen, enc);
11931 }
11932 if (roffset <= 0) return str_duplicate(rb_cString, str);
11933 return rb_str_subseq(str, 0, olen-roffset);
11934}
11935
11936
11937/*
11938 * call-seq:
11939 * strip!(*selectors) -> self or nil
11940 *
11941 * Like String#strip, except that:
11942 *
11943 * - Any modifications are made to +self+.
11944 * - Returns +self+ if any modification are made, +nil+ otherwise.
11945 *
11946 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11947 */
11948
11949static VALUE
11950rb_str_strip_bang(int argc, VALUE *argv, VALUE str)
11951{
11952 char *start;
11953 long olen, loffset, roffset;
11954 rb_encoding *enc;
11955
11956 str_modify_keep_cr(str);
11957 enc = STR_ENC_GET(str);
11958 RSTRING_GETMEM(str, start, olen);
11959
11960 if (argc > 0) {
11961 char table[TR_TABLE_SIZE];
11962 VALUE del = 0, nodel = 0;
11963
11964 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11965 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11966 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
11967 }
11968 else {
11969 loffset = lstrip_offset(str, start, start+olen, enc);
11970 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
11971 }
11972
11973 if (loffset > 0 || roffset > 0) {
11974 long len = olen-roffset;
11975 if (loffset > 0) {
11976 len -= loffset;
11977 memmove(start, start + loffset, len);
11978 }
11979 STR_SET_LEN(str, len);
11980 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11981 return str;
11982 }
11983 return Qnil;
11984}
11985
11986
11987/*
11988 * call-seq:
11989 * strip(*selectors) -> new_string
11990 *
11991 * Returns a copy of +self+ with leading and trailing whitespace removed;
11992 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11993 *
11994 * whitespace = "\x00\t\n\v\f\r "
11995 * s = whitespace + 'abc' + whitespace
11996 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11997 * s.strip # => "abc"
11998 *
11999 * If +selectors+ are given, removes characters of +selectors+ from both ends of +self+:
12000 *
12001 * s = "---abc+++"
12002 * s.strip("-+") # => "abc"
12003 * s.strip("+-") # => "abc"
12004 *
12005 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
12006 * and may use any of its valid forms, including negation, ranges, and escapes:
12007 *
12008 * "01234abc56789".strip("0-9") # "abc"
12009 * "01234abc56789".strip("0-9", "^4-6") # "4abc56"
12010 *
12011 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
12012 */
12013
12014static VALUE
12015rb_str_strip(int argc, VALUE *argv, VALUE str)
12016{
12017 const char *start;
12018 long olen, loffset, roffset;
12019 rb_encoding *enc = STR_ENC_GET(str);
12020
12021 RSTRING_GETMEM(str, start, olen);
12022
12023 if (argc > 0) {
12024 char table[TR_TABLE_SIZE];
12025 VALUE del = 0, nodel = 0;
12026
12027 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12028 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12029 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12030 }
12031 else {
12032 loffset = lstrip_offset(str, start, start+olen, enc);
12033 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12034 }
12035
12036 if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
12037 return rb_str_subseq(str, loffset, olen-loffset-roffset);
12038}
12039
12040static VALUE
12041scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
12042{
12043 VALUE result = Qnil;
12044 long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12045 if (pos >= 0) {
12046 VALUE match = Qnil;
12047 if (BUILTIN_TYPE(pat) == T_STRING) {
12048 end = pos + RSTRING_LEN(pat);
12049 }
12050 else {
12051 match = rb_backref_get();
12052 pos = RMATCH_BEG(match, 0);
12053 end = RMATCH_END(match, 0);
12054 }
12055
12056 if (pos == end) {
12057 rb_encoding *enc = STR_ENC_GET(str);
12058 /*
12059 * Always consume at least one character of the input string
12060 */
12061 if (RSTRING_LEN(str) > end)
12062 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12063 RSTRING_END(str), enc);
12064 else
12065 *start = end + 1;
12066 }
12067 else {
12068 *start = end;
12069 }
12070
12071 if (NIL_P(match) || RMATCH_NREGS(match) == 1) {
12072 result = rb_str_subseq(str, pos, end - pos);
12073 return result;
12074 }
12075 else {
12076 int num_regs = RMATCH_NREGS(match);
12077 result = rb_ary_new2(num_regs);
12078 for (int i = 1; i < num_regs; i++) {
12079 VALUE s = Qnil;
12080 if (RMATCH_BEG(match, i) >= 0) {
12081 s = rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12082 }
12083
12084 rb_ary_push(result, s);
12085 }
12086 }
12087
12088 RB_GC_GUARD(match);
12089 }
12090
12091 return result;
12092}
12093
12094
12095/*
12096 * call-seq:
12097 * scan(pattern) -> array_of_results
12098 * scan(pattern) {|result| ... } -> self
12099 *
12100 * :include: doc/string/scan.rdoc
12101 *
12102 */
12103
12104static VALUE
12105rb_str_scan(VALUE str, VALUE pat)
12106{
12107 VALUE result;
12108 long start = 0;
12109 long last = -1, prev = 0;
12110 const char *p = RSTRING_PTR(str);
12111 long len = RSTRING_LEN(str);
12112
12113 pat = get_pat_quoted(pat, 1);
12114 mustnot_broken(str);
12115 if (!rb_block_given_p()) {
12116 VALUE ary = rb_ary_new();
12117
12118 while (!NIL_P(result = scan_once(str, pat, &start, 0))) {
12119 last = prev;
12120 prev = start;
12121 rb_ary_push(ary, result);
12122 }
12123 if (last >= 0) rb_pat_search(pat, str, last, 1);
12124 else rb_backref_set(Qnil);
12125 return ary;
12126 }
12127
12128 while (!NIL_P(result = scan_once(str, pat, &start, 1))) {
12129 last = prev;
12130 prev = start;
12131 rb_yield(result);
12132 str_mod_check(str, p, len);
12133 }
12134 if (last >= 0) rb_pat_search(pat, str, last, 1);
12135 return str;
12136}
12137
12138
12139/*
12140 * call-seq:
12141 * hex -> integer
12142 *
12143 * Interprets the leading substring of +self+ as hexadecimal, possibly signed;
12144 * returns its value as an integer.
12145 *
12146 * The leading substring is interpreted as hexadecimal when it begins with:
12147 *
12148 * - One or more character representing hexadecimal digits
12149 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
12150 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit:
12151 *
12152 * 'f'.hex # => 15
12153 * '11'.hex # => 17
12154 * 'FFF'.hex # => 4095
12155 * 'fffg'.hex # => 4095
12156 * 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not.
12157 * 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not.
12158 * 'deadbeef'.hex # => 3735928559
12159 *
12160 * - <tt>'0x'</tt> or <tt>'0X'</tt>, followed by one or more hexadecimal digits:
12161 *
12162 * '0xfff'.hex # => 4095
12163 * '0xfffg'.hex # => 4095
12164 *
12165 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
12166 *
12167 * '-fff'.hex # => -4095
12168 * '-0xFFF'.hex # => -4095
12169 *
12170 * For any substring not described above, returns zero:
12171 *
12172 * 'xxx'.hex # => 0
12173 * ''.hex # => 0
12174 *
12175 * Note that, unlike #oct, this method interprets only hexadecimal,
12176 * and not binary, octal, or decimal notations:
12177 *
12178 * '0b111'.hex # => 45329
12179 * '0o777'.hex # => 0
12180 * '0d999'.hex # => 55705
12181 *
12182 * Related: See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
12183 */
12184
12185static VALUE
12186rb_str_hex(VALUE str)
12187{
12188 return rb_str_to_inum(str, 16, FALSE);
12189}
12190
12191
12192/*
12193 * call-seq:
12194 * oct -> integer
12195 *
12196 * Interprets the leading substring of +self+ as octal, binary, decimal, or hexadecimal, possibly signed;
12197 * returns their value as an integer.
12198 *
12199 * In brief:
12200 *
12201 * # Interpreted as octal.
12202 * '777'.oct # => 511
12203 * '777x'.oct # => 511
12204 * '0777'.oct # => 511
12205 * '0o777'.oct # => 511
12206 * '-777'.oct # => -511
12207 * # Not interpreted as octal.
12208 * '0b111'.oct # => 7 # Interpreted as binary.
12209 * '0d999'.oct # => 999 # Interpreted as decimal.
12210 * '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
12211 *
12212 * The leading substring is interpreted as octal when it begins with:
12213 *
12214 * - One or more character representing octal digits
12215 * (each in the range <tt>'0'..'7'</tt>);
12216 * the string to be interpreted ends at the first character that does not represent an octal digit:
12217 *
12218 * '7'.oct @ => 7
12219 * '11'.oct # => 9
12220 * '777'.oct # => 511
12221 * '0777'.oct # => 511
12222 * '7778'.oct # => 511
12223 * '777x'.oct # => 511
12224 *
12225 * - <tt>'0o'</tt>, followed by one or more octal digits:
12226 *
12227 * '0o777'.oct # => 511
12228 * '0o7778'.oct # => 511
12229 *
12230 * The leading substring is _not_ interpreted as octal when it begins with:
12231 *
12232 * - <tt>'0b'</tt>, followed by one or more characters representing binary digits
12233 * (each in the range <tt>'0'..'1'</tt>);
12234 * the string to be interpreted ends at the first character that does not represent a binary digit.
12235 * the string is interpreted as binary digits (base 2):
12236 *
12237 * '0b111'.oct # => 7
12238 * '0b1112'.oct # => 7
12239 *
12240 * - <tt>'0d'</tt>, followed by one or more characters representing decimal digits
12241 * (each in the range <tt>'0'..'9'</tt>);
12242 * the string to be interpreted ends at the first character that does not represent a decimal digit.
12243 * the string is interpreted as decimal digits (base 10):
12244 *
12245 * '0d999'.oct # => 999
12246 * '0d999x'.oct # => 999
12247 *
12248 * - <tt>'0x'</tt>, followed by one or more characters representing hexadecimal digits
12249 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
12250 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit.
12251 * the string is interpreted as hexadecimal digits (base 16):
12252 *
12253 * '0xfff'.oct # => 4095
12254 * '0xfffg'.oct # => 4095
12255 *
12256 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
12257 *
12258 * '-777'.oct # => -511
12259 * '-0777'.oct # => -511
12260 * '-0b111'.oct # => -7
12261 * '-0xfff'.oct # => -4095
12262 *
12263 * For any substring not described above, returns zero:
12264 *
12265 * 'foo'.oct # => 0
12266 * ''.oct # => 0
12267 *
12268 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
12269 */
12270
12271static VALUE
12272rb_str_oct(VALUE str)
12273{
12274 return rb_str_to_inum(str, -8, FALSE);
12275}
12276
12277#ifndef HAVE_CRYPT_R
12278# include "ruby/thread_native.h"
12279# include "ruby/atomic.h"
12280
12281static struct {
12282 rb_nativethread_lock_t lock;
12283} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12284#endif
12285
12286/*
12287 * call-seq:
12288 * crypt(salt_str) -> new_string
12289 *
12290 * Returns the string generated by calling <code>crypt(3)</code>
12291 * standard library function with <code>str</code> and
12292 * <code>salt_str</code>, in this order, as its arguments. Please do
12293 * not use this method any longer. It is legacy; provided only for
12294 * backward compatibility with ruby scripts in earlier days. It is
12295 * bad to use in contemporary programs for several reasons:
12296 *
12297 * * Behaviour of C's <code>crypt(3)</code> depends on the OS it is
12298 * run. The generated string lacks data portability.
12299 *
12300 * * On some OSes such as Mac OS, <code>crypt(3)</code> never fails
12301 * (i.e. silently ends up in unexpected results).
12302 *
12303 * * On some OSes such as Mac OS, <code>crypt(3)</code> is not
12304 * thread safe.
12305 *
12306 * * So-called "traditional" usage of <code>crypt(3)</code> is very
12307 * very very weak. According to its manpage, Linux's traditional
12308 * <code>crypt(3)</code> output has only 2**56 variations; too
12309 * easy to brute force today. And this is the default behaviour.
12310 *
12311 * * In order to make things robust some OSes implement so-called
12312 * "modular" usage. To go through, you have to do a complex
12313 * build-up of the <code>salt_str</code> parameter, by hand.
12314 * Failure in generation of a proper salt string tends not to
12315 * yield any errors; typos in parameters are normally not
12316 * detectable.
12317 *
12318 * * For instance, in the following example, the second invocation
12319 * of String#crypt is wrong; it has a typo in "round=" (lacks
12320 * "s"). However the call does not fail and something unexpected
12321 * is generated.
12322 *
12323 * "foo".crypt("$5$rounds=1000$salt$") # OK, proper usage
12324 * "foo".crypt("$5$round=1000$salt$") # Typo not detected
12325 *
12326 * * Even in the "modular" mode, some hash functions are considered
12327 * archaic and no longer recommended at all; for instance module
12328 * <code>$1$</code> is officially abandoned by its author: see
12329 * http://phk.freebsd.dk/sagas/md5crypt_eol/ . For another
12330 * instance module <code>$3$</code> is considered completely
12331 * broken: see the manpage of FreeBSD.
12332 *
12333 * * On some OS such as Mac OS, there is no modular mode. Yet, as
12334 * written above, <code>crypt(3)</code> on Mac OS never fails.
12335 * This means even if you build up a proper salt string it
12336 * generates a traditional DES hash anyways, and there is no way
12337 * for you to be aware of.
12338 *
12339 * "foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
12340 *
12341 * If for some reason you cannot migrate to other secure contemporary
12342 * password hashing algorithms, install the string-crypt gem and
12343 * <code>require 'string/crypt'</code> to continue using it.
12344 */
12345
12346static VALUE
12347rb_str_crypt(VALUE str, VALUE salt)
12348{
12349#ifdef HAVE_CRYPT_R
12350 VALUE databuf;
12351 struct crypt_data *data;
12352# define CRYPT_END() ALLOCV_END(databuf)
12353#else
12354 char *tmp_buf;
12355 extern char *crypt(const char *, const char *);
12356# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12357#endif
12358 VALUE result;
12359 const char *s, *saltp, *res;
12360#ifdef BROKEN_CRYPT
12361 char salt_8bit_clean[3];
12362#endif
12363
12364 StringValue(salt);
12365 mustnot_wchar(str);
12366 mustnot_wchar(salt);
12367 s = StringValueCStr(str);
12368 saltp = RSTRING_PTR(salt);
12369 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12370 rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
12371 }
12372
12373#ifdef BROKEN_CRYPT
12374 if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) {
12375 salt_8bit_clean[0] = saltp[0] & 0x7f;
12376 salt_8bit_clean[1] = saltp[1] & 0x7f;
12377 salt_8bit_clean[2] = '\0';
12378 saltp = salt_8bit_clean;
12379 }
12380#endif
12381#ifdef HAVE_CRYPT_R
12382 data = ALLOCV(databuf, sizeof(struct crypt_data));
12383# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12384 data->initialized = 0;
12385# endif
12386 res = crypt_r(s, saltp, data);
12387#else
12388 rb_nativethread_lock_lock(&crypt_mutex.lock);
12389 res = crypt(s, saltp);
12390#endif
12391 if (!res) {
12392 int err = errno;
12393 CRYPT_END();
12394 rb_syserr_fail(err, "crypt");
12395 }
12396#ifdef HAVE_CRYPT_R
12397 result = rb_str_new_cstr(res);
12398 CRYPT_END();
12399#else
12400 // We need to copy this buffer because it's static and we need to unlock the mutex
12401 // before allocating a new object (the string to be returned). If we allocate while
12402 // holding the lock, we could run GC which fires the VM barrier and causes a deadlock
12403 // if other ractors are waiting on this lock.
12404 size_t res_size = strlen(res);
12405 tmp_buf = ALLOCA_N(char, res_size); // should be small enough to alloca
12406 memcpy(tmp_buf, res, res_size);
12407 CRYPT_END();
12408 result = rb_str_new(tmp_buf, res_size);
12409#endif
12410 return result;
12411}
12412
12413
12414/*
12415 * call-seq:
12416 * ord -> integer
12417 *
12418 * :include: doc/string/ord.rdoc
12419 *
12420 */
12421
12422static VALUE
12423rb_str_ord(VALUE s)
12424{
12425 unsigned int c;
12426
12427 c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
12428 return UINT2NUM(c);
12429}
12430/*
12431 * call-seq:
12432 * sum(n = 16) -> integer
12433 *
12434 * :include: doc/string/sum.rdoc
12435 *
12436 */
12437
12438static VALUE
12439rb_str_sum(int argc, VALUE *argv, VALUE str)
12440{
12441 int bits = 16;
12442 char *ptr, *p, *pend;
12443 long len;
12444 VALUE sum = INT2FIX(0);
12445 unsigned long sum0 = 0;
12446
12447 if (rb_check_arity(argc, 0, 1) && (bits = NUM2INT(argv[0])) < 0) {
12448 bits = 0;
12449 }
12450 ptr = p = RSTRING_PTR(str);
12451 len = RSTRING_LEN(str);
12452 pend = p + len;
12453
12454 while (p < pend) {
12455 if (FIXNUM_MAX - UCHAR_MAX < sum0) {
12456 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12457 str_mod_check(str, ptr, len);
12458 sum0 = 0;
12459 }
12460 sum0 += (unsigned char)*p;
12461 p++;
12462 }
12463
12464 if (bits == 0) {
12465 if (sum0) {
12466 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12467 }
12468 }
12469 else {
12470 if (sum == INT2FIX(0)) {
12471 if (bits < (int)sizeof(long)*CHAR_BIT) {
12472 sum0 &= (((unsigned long)1)<<bits)-1;
12473 }
12474 sum = LONG2FIX(sum0);
12475 }
12476 else {
12477 VALUE mod;
12478
12479 if (sum0) {
12480 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12481 }
12482
12483 mod = rb_funcall(INT2FIX(1), idLTLT, 1, INT2FIX(bits));
12484 mod = rb_funcall(mod, '-', 1, INT2FIX(1));
12485 sum = rb_funcall(sum, '&', 1, mod);
12486 }
12487 }
12488 return sum;
12489}
12490
12491static VALUE
12492rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
12493{
12494 rb_encoding *enc;
12495 VALUE w;
12496 long width, len, flen = 1, fclen = 1;
12497 VALUE res;
12498 char *p;
12499 const char *f = " ";
12500 long n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12501 VALUE pad;
12502 int singlebyte = 1, cr;
12503 int termlen;
12504
12505 rb_scan_args(argc, argv, "11", &w, &pad);
12506 enc = STR_ENC_GET(str);
12507 width = NUM2LONG(w);
12508 if (argc == 2) {
12509 StringValue(pad);
12510 enc = rb_enc_check(str, pad);
12511 f = RSTRING_PTR(pad);
12512 flen = RSTRING_LEN(pad);
12513 fclen = str_strlen(pad, enc); /* rb_enc_check */
12514 singlebyte = single_byte_optimizable(pad);
12515 if (flen == 0 || fclen == 0) {
12516 rb_raise(rb_eArgError, "zero width padding");
12517 }
12518 }
12519 termlen = rb_enc_mbminlen(enc);
12520 len = str_strlen(str, enc); /* rb_enc_check */
12521 if (width < 0 || len >= width) return str_duplicate(rb_cString, str);
12522 n = width - len;
12523 llen = (jflag == 'l') ? 0 : ((jflag == 'r') ? n : n/2);
12524 rlen = n - llen;
12525 cr = ENC_CODERANGE(str);
12526 if (flen > 1) {
12527 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12528 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12529 }
12530 size = RSTRING_LEN(str);
12531 if ((len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
12532 (len *= flen) >= LONG_MAX - llen2 - rlen2 ||
12533 (len += llen2 + rlen2) >= LONG_MAX - size) {
12534 rb_raise(rb_eArgError, "argument too big");
12535 }
12536 len += size;
12537 res = str_enc_new(rb_cString, 0, len, enc);
12538 p = RSTRING_PTR(res);
12539 if (flen <= 1) {
12540 memset(p, *f, llen);
12541 p += llen;
12542 }
12543 else {
12544 while (llen >= fclen) {
12545 memcpy(p,f,flen);
12546 p += flen;
12547 llen -= fclen;
12548 }
12549 if (llen > 0) {
12550 memcpy(p, f, llen2);
12551 p += llen2;
12552 }
12553 }
12554 memcpy(p, RSTRING_PTR(str), size);
12555 p += size;
12556 if (flen <= 1) {
12557 memset(p, *f, rlen);
12558 p += rlen;
12559 }
12560 else {
12561 while (rlen >= fclen) {
12562 memcpy(p,f,flen);
12563 p += flen;
12564 rlen -= fclen;
12565 }
12566 if (rlen > 0) {
12567 memcpy(p, f, rlen2);
12568 p += rlen2;
12569 }
12570 }
12571 TERM_FILL(p, termlen);
12572 STR_SET_LEN(res, p-RSTRING_PTR(res));
12573
12574 if (argc == 2)
12575 cr = ENC_CODERANGE_AND(cr, ENC_CODERANGE(pad));
12576 if (cr != ENC_CODERANGE_BROKEN)
12577 ENC_CODERANGE_SET(res, cr);
12578
12579 RB_GC_GUARD(pad);
12580 return res;
12581}
12582
12583
12584/*
12585 * call-seq:
12586 * ljust(width, pad_string = ' ') -> new_string
12587 *
12588 * :include: doc/string/ljust.rdoc
12589 *
12590 */
12591
12592static VALUE
12593rb_str_ljust(int argc, VALUE *argv, VALUE str)
12594{
12595 return rb_str_justify(argc, argv, str, 'l');
12596}
12597
12598/*
12599 * call-seq:
12600 * rjust(width, pad_string = ' ') -> new_string
12601 *
12602 * :include: doc/string/rjust.rdoc
12603 *
12604 */
12605
12606static VALUE
12607rb_str_rjust(int argc, VALUE *argv, VALUE str)
12608{
12609 return rb_str_justify(argc, argv, str, 'r');
12610}
12611
12612
12613/*
12614 * call-seq:
12615 * center(size, pad_string = ' ') -> new_string
12616 *
12617 * :include: doc/string/center.rdoc
12618 *
12619 */
12620
12621static VALUE
12622rb_str_center(int argc, VALUE *argv, VALUE str)
12623{
12624 return rb_str_justify(argc, argv, str, 'c');
12625}
12626
12627/*
12628 * call-seq:
12629 * partition(pattern) -> [pre_match, first_match, post_match]
12630 *
12631 * :include: doc/string/partition.rdoc
12632 *
12633 */
12634
12635static VALUE
12636rb_str_partition(VALUE str, VALUE sep)
12637{
12638 long pos;
12639
12640 sep = get_pat_quoted(sep, 0);
12641 if (RB_TYPE_P(sep, T_REGEXP)) {
12642 if (rb_reg_search(sep, str, 0, 0) < 0) {
12643 goto failed;
12644 }
12645 VALUE match = rb_backref_get();
12646
12647 pos = RMATCH_BEG(match, 0);
12648 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12649 }
12650 else {
12651 pos = rb_str_index(str, sep, 0);
12652 if (pos < 0) goto failed;
12653 }
12654
12655 long rpos = pos + RSTRING_LEN(sep);
12656 if (rpos > RSTRING_LEN(str)) goto failed;
12657 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12658 sep,
12659 rb_str_subseq(str, rpos, RSTRING_LEN(str)-rpos));
12660
12661 failed:
12662 return rb_ary_new3(3, str_duplicate(rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12663}
12664
12665/*
12666 * call-seq:
12667 * rpartition(pattern) -> [pre_match, last_match, post_match]
12668 *
12669 * :include: doc/string/rpartition.rdoc
12670 *
12671 */
12672
12673static VALUE
12674rb_str_rpartition(VALUE str, VALUE sep)
12675{
12676 long pos = RSTRING_LEN(str);
12677
12678 sep = get_pat_quoted(sep, 0);
12679 if (RB_TYPE_P(sep, T_REGEXP)) {
12680 if (rb_reg_search(sep, str, pos, 1) < 0) {
12681 goto failed;
12682 }
12683 VALUE match = rb_backref_get();
12684
12685 pos = RMATCH_BEG(match, 0);
12686 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12687 }
12688 else {
12689 pos = rb_str_sublen(str, pos);
12690 pos = rb_str_rindex(str, sep, pos);
12691 if (pos < 0) {
12692 goto failed;
12693 }
12694 }
12695
12696 long rpos = pos + RSTRING_LEN(sep);
12697 if (rpos > RSTRING_LEN(str)) goto failed;
12698 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12699 sep,
12700 rb_str_subseq(str, rpos, RSTRING_LEN(str)-rpos));
12701 failed:
12702 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(rb_cString, str));
12703}
12704
12705/*
12706 * call-seq:
12707 * start_with?(*patterns) -> true or false
12708 *
12709 * :include: doc/string/start_with_p.rdoc
12710 *
12711 */
12712
12713static VALUE
12714rb_str_start_with(int argc, VALUE *argv, VALUE str)
12715{
12716 int i;
12717
12718 for (i=0; i<argc; i++) {
12719 VALUE tmp = argv[i];
12720 if (RB_TYPE_P(tmp, T_REGEXP)) {
12721 if (rb_reg_start_with_p(tmp, str))
12722 return Qtrue;
12723 }
12724 else {
12725 const char *p, *s, *e;
12726 long slen, tlen;
12727 rb_encoding *enc;
12728
12729 StringValue(tmp);
12730 enc = rb_enc_check(str, tmp);
12731 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12732 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12733 p = RSTRING_PTR(str);
12734 e = p + slen;
12735 s = p + tlen;
12736 if (!at_char_right_boundary(p, s, e, enc))
12737 continue;
12738 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12739 return Qtrue;
12740 }
12741 }
12742 return Qfalse;
12743}
12744
12745/*
12746 * call-seq:
12747 * end_with?(*strings) -> true or false
12748 *
12749 * :include: doc/string/end_with_p.rdoc
12750 *
12751 */
12752
12753static VALUE
12754rb_str_end_with(int argc, VALUE *argv, VALUE str)
12755{
12756 int i;
12757
12758 for (i=0; i<argc; i++) {
12759 VALUE tmp = argv[i];
12760 const char *p, *s, *e;
12761 long slen, tlen;
12762 rb_encoding *enc;
12763
12764 StringValue(tmp);
12765 enc = rb_enc_check(str, tmp);
12766 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12767 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12768 p = RSTRING_PTR(str);
12769 e = p + slen;
12770 s = e - tlen;
12771 if (!at_char_boundary(p, s, e, enc))
12772 continue;
12773 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12774 return Qtrue;
12775 }
12776 return Qfalse;
12777}
12778
12788static long
12789deleted_prefix_length(VALUE str, VALUE prefix)
12790{
12791 const char *strptr, *prefixptr;
12792 long olen, prefixlen;
12793 rb_encoding *enc = rb_enc_get(str);
12794
12795 StringValue(prefix);
12796
12797 if (!is_broken_string(prefix) ||
12798 !rb_enc_asciicompat(enc) ||
12799 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12800 enc = rb_enc_check(str, prefix);
12801 }
12802
12803 /* return 0 if not start with prefix */
12804 prefixlen = RSTRING_LEN(prefix);
12805 if (prefixlen <= 0) return 0;
12806 olen = RSTRING_LEN(str);
12807 if (olen < prefixlen) return 0;
12808 strptr = RSTRING_PTR(str);
12809 prefixptr = RSTRING_PTR(prefix);
12810 if (memcmp(strptr, prefixptr, prefixlen) != 0) return 0;
12811 if (is_broken_string(prefix)) {
12812 if (!is_broken_string(str)) {
12813 /* prefix in a valid string cannot be broken */
12814 return 0;
12815 }
12816 const char *strend = strptr + olen;
12817 const char *after_prefix = strptr + prefixlen;
12818 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12819 /* prefix does not end at char-boundary */
12820 return 0;
12821 }
12822 }
12823 /* prefix part in `str` also should be valid. */
12824
12825 return prefixlen;
12826}
12827
12828/*
12829 * call-seq:
12830 * delete_prefix!(prefix) -> self or nil
12831 *
12832 * Like String#delete_prefix, except that +self+ is modified in place;
12833 * returns +self+ if the prefix is removed, +nil+ otherwise.
12834 *
12835 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12836 */
12837
12838static VALUE
12839rb_str_delete_prefix_bang(VALUE str, VALUE prefix)
12840{
12841 long prefixlen;
12842 str_modify_keep_cr(str);
12843
12844 prefixlen = deleted_prefix_length(str, prefix);
12845 if (prefixlen <= 0) return Qnil;
12846
12847 return rb_str_drop_bytes(str, prefixlen);
12848}
12849
12850/*
12851 * call-seq:
12852 * delete_prefix(prefix) -> new_string
12853 *
12854 * :include: doc/string/delete_prefix.rdoc
12855 *
12856 */
12857
12858static VALUE
12859rb_str_delete_prefix(VALUE str, VALUE prefix)
12860{
12861 long prefixlen;
12862
12863 prefixlen = deleted_prefix_length(str, prefix);
12864 if (prefixlen <= 0) return str_duplicate(rb_cString, str);
12865
12866 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
12867}
12868
12878static long
12879deleted_suffix_length(VALUE str, VALUE suffix)
12880{
12881 const char *strptr, *suffixptr;
12882 long olen, suffixlen;
12883 rb_encoding *enc;
12884
12885 StringValue(suffix);
12886 if (is_broken_string(suffix)) return 0;
12887 enc = rb_enc_check(str, suffix);
12888
12889 /* return 0 if not start with suffix */
12890 suffixlen = RSTRING_LEN(suffix);
12891 if (suffixlen <= 0) return 0;
12892 olen = RSTRING_LEN(str);
12893 if (olen < suffixlen) return 0;
12894 strptr = RSTRING_PTR(str);
12895 suffixptr = RSTRING_PTR(suffix);
12896 const char *strend = strptr + olen;
12897 const char *before_suffix = strend - suffixlen;
12898 if (memcmp(before_suffix, suffixptr, suffixlen) != 0) return 0;
12899 if (!at_char_boundary(strptr, before_suffix, strend, enc)) return 0;
12900
12901 return suffixlen;
12902}
12903
12904/*
12905 * call-seq:
12906 * delete_suffix!(suffix) -> self or nil
12907 *
12908 * Like String#delete_suffix, except that +self+ is modified in place;
12909 * returns +self+ if the suffix is removed, +nil+ otherwise.
12910 *
12911 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12912 */
12913
12914static VALUE
12915rb_str_delete_suffix_bang(VALUE str, VALUE suffix)
12916{
12917 long suffixlen;
12918 str_modifiable(str);
12919
12920 suffixlen = deleted_suffix_length(str, suffix);
12921 if (suffixlen <= 0) return Qnil;
12922
12923 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
12924}
12925
12926/*
12927 * call-seq:
12928 * delete_suffix(suffix) -> new_string
12929 *
12930 * :include: doc/string/delete_suffix.rdoc
12931 *
12932 */
12933
12934static VALUE
12935rb_str_delete_suffix(VALUE str, VALUE suffix)
12936{
12937 long suffixlen;
12938
12939 suffixlen = deleted_suffix_length(str, suffix);
12940 if (suffixlen <= 0) return str_duplicate(rb_cString, str);
12941
12942 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
12943}
12944
12945void
12946rb_str_setter(VALUE val, ID id, VALUE *var)
12947{
12948 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING)) {
12949 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
12950 }
12951 *var = val;
12952}
12953
12954static void
12955nil_setter_warning(ID id)
12956{
12957 rb_warn_deprecated("non-nil '%"PRIsVALUE"'", NULL, rb_id2str(id));
12958}
12959
12960void
12961rb_deprecated_str_setter(VALUE val, ID id, VALUE *var)
12962{
12963 rb_str_setter(val, id, var);
12964 if (!NIL_P(*var)) {
12965 nil_setter_warning(id);
12966 }
12967}
12968
12969static void
12970rb_fs_setter(VALUE val, ID id, VALUE *var)
12971{
12972 val = rb_fs_check(val);
12973 if (!val) {
12974 rb_raise(rb_eTypeError,
12975 "value of %"PRIsVALUE" must be String or Regexp",
12976 rb_id2str(id));
12977 }
12978 if (!NIL_P(val)) {
12979 nil_setter_warning(id);
12980 }
12981 *var = val;
12982}
12983
12984
12985/*
12986 * call-seq:
12987 * force_encoding(encoding) -> self
12988 *
12989 * :include: doc/string/force_encoding.rdoc
12990 *
12991 */
12992
12993static VALUE
12994rb_str_force_encoding(VALUE str, VALUE enc)
12995{
12996 str_modifiable(str);
12997
12998 rb_encoding *encoding = rb_to_encoding(enc);
12999 int idx = rb_enc_to_index(encoding);
13000
13001 // If the encoding is unchanged, we do nothing.
13002 if (ENCODING_GET(str) == idx) {
13003 return str;
13004 }
13005
13006 rb_enc_associate_index(str, idx);
13007
13008 // If the coderange was 7bit and the new encoding is ASCII-compatible
13009 // we can keep the coderange.
13010 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT && encoding && rb_enc_asciicompat(encoding)) {
13011 return str;
13012 }
13013
13015 return str;
13016}
13017
13018/*
13019 * call-seq:
13020 * b -> new_string
13021 *
13022 * :include: doc/string/b.rdoc
13023 *
13024 */
13025
13026static VALUE
13027rb_str_b(VALUE str)
13028{
13029 VALUE str2;
13030 if (STR_EMBED_P(str)) {
13031 str2 = str_alloc_embed(rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13032 }
13033 else {
13034 str2 = str_alloc_heap(rb_cString);
13035 }
13036 str_replace_shared_without_enc(str2, str);
13037
13038 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13039 // BINARY strings can never be broken; they're either 7-bit ASCII or VALID.
13040 // If we know the receiver's code range then we know the result's code range.
13041 int cr = ENC_CODERANGE(str);
13042 switch (cr) {
13043 case ENC_CODERANGE_7BIT:
13045 break;
13049 break;
13050 default:
13051 ENC_CODERANGE_CLEAR(str2);
13052 break;
13053 }
13054 }
13055
13056 return str2;
13057}
13058
13059/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
13060static VALUE
13061rb_str_valid_encoding_p(VALUE str)
13062{
13063 int cr = rb_enc_str_coderange(str);
13064
13065 return RBOOL(cr != ENC_CODERANGE_BROKEN);
13066}
13067
13068/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
13069static VALUE
13070rb_str_is_ascii_only_p(VALUE str)
13071{
13072 int cr = rb_enc_str_coderange(str);
13073
13074 return RBOOL(cr == ENC_CODERANGE_7BIT);
13075}
13076
13077VALUE
13079{
13080 static const char ellipsis[] = "...";
13081 const long ellipsislen = sizeof(ellipsis) - 1;
13082 rb_encoding *const enc = rb_enc_get(str);
13083 const long blen = RSTRING_LEN(str);
13084 const char *const p = RSTRING_PTR(str), *e = p + blen;
13085 VALUE estr, ret = 0;
13086
13087 if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
13088 if (len * rb_enc_mbminlen(enc) >= blen ||
13089 (e = rb_enc_nth(p, e, len, enc)) - p == blen) {
13090 ret = str;
13091 }
13092 else if (len <= ellipsislen ||
13093 !(e = rb_enc_step_back(p, e, e, len = ellipsislen, enc))) {
13094 if (rb_enc_asciicompat(enc)) {
13095 ret = rb_str_new(ellipsis, len);
13096 rb_enc_associate(ret, enc);
13097 }
13098 else {
13099 estr = rb_usascii_str_new(ellipsis, len);
13100 ret = rb_str_encode(estr, rb_enc_from_encoding(enc), 0, Qnil);
13101 }
13102 }
13103 else if (ret = rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13104 rb_str_cat(ret, ellipsis, ellipsislen);
13105 }
13106 else {
13107 estr = rb_str_encode(rb_usascii_str_new(ellipsis, ellipsislen),
13108 rb_enc_from_encoding(enc), 0, Qnil);
13109 rb_str_append(ret, estr);
13110 }
13111 return ret;
13112}
13113
13114static VALUE
13115str_compat_and_valid(VALUE str, rb_encoding *enc)
13116{
13117 int cr;
13118 str = StringValue(str);
13119 cr = rb_enc_str_coderange(str);
13120 if (cr == ENC_CODERANGE_BROKEN) {
13121 rb_raise(rb_eArgError, "replacement must be valid byte sequence '%+"PRIsVALUE"'", str);
13122 }
13123 else {
13124 rb_encoding *e = STR_ENC_GET(str);
13125 if (cr == ENC_CODERANGE_7BIT ? rb_enc_mbminlen(enc) != 1 : enc != e) {
13126 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
13127 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13128 }
13129 }
13130 return str;
13131}
13132
13133static VALUE enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr);
13134
13135VALUE
13137{
13138 rb_encoding *enc = STR_ENC_GET(str);
13139 return enc_str_scrub(enc, str, repl, ENC_CODERANGE(str));
13140}
13141
13142VALUE
13143rb_enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl)
13144{
13145 int cr = ENC_CODERANGE_UNKNOWN;
13146 if (enc == STR_ENC_GET(str)) {
13147 /* cached coderange makes sense only when enc equals the
13148 * actual encoding of str */
13149 cr = ENC_CODERANGE(str);
13150 }
13151 return enc_str_scrub(enc, str, repl, cr);
13152}
13153
13154static VALUE
13155enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
13156{
13157 int encidx;
13158 VALUE buf = Qnil;
13159 const char *rep, *p, *e, *p1, *sp;
13160 long replen = -1;
13161 long slen;
13162
13163 if (rb_block_given_p()) {
13164 if (!NIL_P(repl))
13165 rb_raise(rb_eArgError, "both of block and replacement given");
13166 replen = 0;
13167 }
13168
13169 if (ENC_CODERANGE_CLEAN_P(cr))
13170 return Qnil;
13171
13172 if (!NIL_P(repl)) {
13173 repl = str_compat_and_valid(repl, enc);
13174 }
13175
13176 if (rb_enc_dummy_p(enc)) {
13177 return Qnil;
13178 }
13179 encidx = rb_enc_to_index(enc);
13180
13181#define DEFAULT_REPLACE_CHAR(str) do { \
13182 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13183 rep = replace; replen = (int)sizeof(replace); \
13184 } while (0)
13185
13186 slen = RSTRING_LEN(str);
13187 p = RSTRING_PTR(str);
13188 e = RSTRING_END(str);
13189 p1 = p;
13190 sp = p;
13191
13192 if (rb_enc_asciicompat(enc)) {
13193 int rep7bit_p;
13194 if (!replen) {
13195 rep = NULL;
13196 rep7bit_p = FALSE;
13197 }
13198 else if (!NIL_P(repl)) {
13199 rep = RSTRING_PTR(repl);
13200 replen = RSTRING_LEN(repl);
13201 rep7bit_p = (ENC_CODERANGE(repl) == ENC_CODERANGE_7BIT);
13202 }
13203 else if (encidx == rb_utf8_encindex()) {
13204 DEFAULT_REPLACE_CHAR("\xEF\xBF\xBD");
13205 rep7bit_p = FALSE;
13206 }
13207 else {
13208 DEFAULT_REPLACE_CHAR("?");
13209 rep7bit_p = TRUE;
13210 }
13211 cr = ENC_CODERANGE_7BIT;
13212
13213 p = search_nonascii(p, e);
13214 if (!p) {
13215 p = e;
13216 }
13217 while (p < e) {
13218 int ret = rb_enc_precise_mbclen(p, e, enc);
13219 if (MBCLEN_NEEDMORE_P(ret)) {
13220 break;
13221 }
13222 else if (MBCLEN_CHARFOUND_P(ret)) {
13224 p += MBCLEN_CHARFOUND_LEN(ret);
13225 /* After a multibyte character, fast-skip the following ASCII run. */
13226 p = search_nonascii(p, e);
13227 if (!p) {
13228 p = e;
13229 break;
13230 }
13231 }
13232 else if (MBCLEN_INVALID_P(ret)) {
13233 /*
13234 * p1~p: valid ascii/multibyte chars
13235 * p ~e: invalid bytes + unknown bytes
13236 */
13237 long clen = rb_enc_mbmaxlen(enc);
13238 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
13239 if (p > p1) {
13240 rb_str_buf_cat(buf, p1, p - p1);
13241 }
13242
13243 if (e - p < clen) clen = e - p;
13244 if (clen <= 2) {
13245 clen = 1;
13246 }
13247 else {
13248 const char *q = p;
13249 clen--;
13250 for (; clen > 1; clen--) {
13251 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13252 if (MBCLEN_NEEDMORE_P(ret)) break;
13253 if (MBCLEN_INVALID_P(ret)) continue;
13255 }
13256 }
13257 if (rep) {
13258 rb_str_buf_cat(buf, rep, replen);
13259 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
13260 }
13261 else {
13262 repl = rb_yield(rb_enc_str_new(p, clen, enc));
13263 str_mod_check(str, sp, slen);
13264 repl = str_compat_and_valid(repl, enc);
13265 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13268 }
13269 p += clen;
13270 p1 = p;
13271 p = search_nonascii(p, e);
13272 if (!p) {
13273 p = e;
13274 break;
13275 }
13276 }
13277 else {
13279 }
13280 }
13281 if (NIL_P(buf)) {
13282 if (p == e) {
13283 ENC_CODERANGE_SET(str, cr);
13284 return Qnil;
13285 }
13286 buf = rb_str_buf_new(RSTRING_LEN(str));
13287 }
13288 if (p1 < p) {
13289 rb_str_buf_cat(buf, p1, p - p1);
13290 }
13291 if (p < e) {
13292 if (rep) {
13293 rb_str_buf_cat(buf, rep, replen);
13294 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
13295 }
13296 else {
13297 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
13298 str_mod_check(str, sp, slen);
13299 repl = str_compat_and_valid(repl, enc);
13300 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13303 }
13304 }
13305 }
13306 else {
13307 /* ASCII incompatible */
13308 long mbminlen = rb_enc_mbminlen(enc);
13309 if (!replen) {
13310 rep = NULL;
13311 }
13312 else if (!NIL_P(repl)) {
13313 rep = RSTRING_PTR(repl);
13314 replen = RSTRING_LEN(repl);
13315 }
13316 else if (encidx == ENCINDEX_UTF_16BE) {
13317 DEFAULT_REPLACE_CHAR("\xFF\xFD");
13318 }
13319 else if (encidx == ENCINDEX_UTF_16LE) {
13320 DEFAULT_REPLACE_CHAR("\xFD\xFF");
13321 }
13322 else if (encidx == ENCINDEX_UTF_32BE) {
13323 DEFAULT_REPLACE_CHAR("\x00\x00\xFF\xFD");
13324 }
13325 else if (encidx == ENCINDEX_UTF_32LE) {
13326 DEFAULT_REPLACE_CHAR("\xFD\xFF\x00\x00");
13327 }
13328 else {
13329 DEFAULT_REPLACE_CHAR("?");
13330 }
13331
13332 while (p < e) {
13333 int ret = rb_enc_precise_mbclen(p, e, enc);
13334 if (MBCLEN_NEEDMORE_P(ret)) {
13335 break;
13336 }
13337 else if (MBCLEN_CHARFOUND_P(ret)) {
13338 p += MBCLEN_CHARFOUND_LEN(ret);
13339 }
13340 else if (MBCLEN_INVALID_P(ret)) {
13341 const char *q = p;
13342 long clen = rb_enc_mbmaxlen(enc);
13343 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
13344 if (p > p1) rb_str_buf_cat(buf, p1, p - p1);
13345
13346 if (e - p < clen) clen = e - p;
13347 if (clen <= mbminlen * 2) {
13348 clen = mbminlen;
13349 }
13350 else {
13351 clen -= mbminlen;
13352 for (; clen > mbminlen; clen-=mbminlen) {
13353 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13354 if (MBCLEN_NEEDMORE_P(ret)) break;
13355 if (MBCLEN_INVALID_P(ret)) continue;
13357 }
13358 }
13359 if (rep) {
13360 rb_str_buf_cat(buf, rep, replen);
13361 }
13362 else {
13363 repl = rb_yield(rb_enc_str_new(p, clen, enc));
13364 str_mod_check(str, sp, slen);
13365 repl = str_compat_and_valid(repl, enc);
13366 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13367 }
13368 p += clen;
13369 p1 = p;
13370 }
13371 else {
13373 }
13374 }
13375 if (NIL_P(buf)) {
13376 if (p == e) {
13378 return Qnil;
13379 }
13380 buf = rb_str_buf_new(RSTRING_LEN(str));
13381 }
13382 if (p1 < p) {
13383 rb_str_buf_cat(buf, p1, p - p1);
13384 }
13385 if (p < e) {
13386 if (rep) {
13387 rb_str_buf_cat(buf, rep, replen);
13388 }
13389 else {
13390 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
13391 str_mod_check(str, sp, slen);
13392 repl = str_compat_and_valid(repl, enc);
13393 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13394 }
13395 }
13397 }
13398 ENCODING_CODERANGE_SET(buf, rb_enc_to_index(enc), cr);
13399 return buf;
13400}
13401
13402/*
13403 * call-seq:
13404 * scrub(replacement_string = default_replacement_string) -> new_string
13405 * scrub{|sequence| ... } -> new_string
13406 *
13407 * :include: doc/string/scrub.rdoc
13408 *
13409 */
13410static VALUE
13411str_scrub(int argc, VALUE *argv, VALUE str)
13412{
13413 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13414 VALUE new = rb_str_scrub(str, repl);
13415 return NIL_P(new) ? str_duplicate(rb_cString, str): new;
13416}
13417
13418/*
13419 * call-seq:
13420 * scrub!(replacement_string = default_replacement_string) -> self
13421 * scrub!{|sequence| ... } -> self
13422 *
13423 * Like String#scrub, except that:
13424 *
13425 * - Any replacements are made in +self+.
13426 * - Returns +self+.
13427 *
13428 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13429 *
13430 */
13431static VALUE
13432str_scrub_bang(int argc, VALUE *argv, VALUE str)
13433{
13434 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13435 VALUE new = rb_str_scrub(str, repl);
13436 if (!NIL_P(new)) rb_str_replace(str, new);
13437 return str;
13438}
13439
13440static ID id_normalize;
13441static ID id_normalized_p;
13442static VALUE mUnicodeNormalize;
13443
13444static VALUE
13445unicode_normalize_common(int argc, VALUE *argv, VALUE str, ID id)
13446{
13447 static int UnicodeNormalizeRequired = 0;
13448 VALUE argv2[2];
13449
13450 if (!UnicodeNormalizeRequired) {
13451 rb_require("unicode_normalize/normalize.rb");
13452 UnicodeNormalizeRequired = 1;
13453 }
13454 argv2[0] = str;
13455 if (rb_check_arity(argc, 0, 1)) argv2[1] = argv[0];
13456 return rb_funcallv(mUnicodeNormalize, id, argc+1, argv2);
13457}
13458
13459/*
13460 * call-seq:
13461 * unicode_normalize(form = :nfc) -> string
13462 *
13463 * :include: doc/string/unicode_normalize.rdoc
13464 *
13465 */
13466static VALUE
13467rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
13468{
13469 return unicode_normalize_common(argc, argv, str, id_normalize);
13470}
13471
13472/*
13473 * call-seq:
13474 * unicode_normalize!(form = :nfc) -> self
13475 *
13476 * Like String#unicode_normalize, except that the normalization
13477 * is performed on +self+ (not on a copy of +self+).
13478 *
13479 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13480 *
13481 */
13482static VALUE
13483rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
13484{
13485 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13486}
13487
13488/* call-seq:
13489 * unicode_normalized?(form = :nfc) -> true or false
13490 *
13491 * Returns whether +self+ is in the given +form+ of Unicode normalization;
13492 * see String#unicode_normalize.
13493 *
13494 * The +form+ must be one of +:nfc+, +:nfd+, +:nfkc+, or +:nfkd+.
13495 *
13496 * Examples:
13497 *
13498 * "a\u0300".unicode_normalized? # => false
13499 * "a\u0300".unicode_normalized?(:nfd) # => true
13500 * "\u00E0".unicode_normalized? # => true
13501 * "\u00E0".unicode_normalized?(:nfd) # => false
13502 *
13503 *
13504 * Raises an exception if +self+ is not in a Unicode encoding:
13505 *
13506 * s = "\xE0".force_encoding(Encoding::ISO_8859_1)
13507 * s.unicode_normalized? # Raises Encoding::CompatibilityError
13508 *
13509 * Related: see {Querying}[rdoc-ref:String@Querying].
13510 */
13511static VALUE
13512rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
13513{
13514 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13515}
13516
13517/**********************************************************************
13518 * Document-class: Symbol
13519 *
13520 * A +Symbol+ object represents a named identifier inside the Ruby interpreter.
13521 *
13522 * You can create a +Symbol+ object explicitly with:
13523 *
13524 * - A {symbol literal}[rdoc-ref:syntax/literals.rdoc@Symbol+Literals].
13525 *
13526 * The same +Symbol+ object will be
13527 * created for a given name or string for the duration of a program's
13528 * execution, regardless of the context or meaning of that name. Thus
13529 * if <code>Fred</code> is a constant in one context, a method in
13530 * another, and a class in a third, the +Symbol+ <code>:Fred</code>
13531 * will be the same object in all three contexts.
13532 *
13533 * module One
13534 * class Fred
13535 * end
13536 * $f1 = :Fred
13537 * end
13538 * module Two
13539 * Fred = 1
13540 * $f2 = :Fred
13541 * end
13542 * def Fred()
13543 * end
13544 * $f3 = :Fred
13545 * $f1.object_id #=> 2514190
13546 * $f2.object_id #=> 2514190
13547 * $f3.object_id #=> 2514190
13548 *
13549 * Constant, method, and variable names are returned as symbols:
13550 *
13551 * module One
13552 * Two = 2
13553 * def three; 3 end
13554 * @four = 4
13555 * @@five = 5
13556 * $six = 6
13557 * end
13558 * seven = 7
13559 *
13560 * One.constants
13561 * # => [:Two]
13562 * One.instance_methods(true)
13563 * # => [:three]
13564 * One.instance_variables
13565 * # => [:@four]
13566 * One.class_variables
13567 * # => [:@@five]
13568 * global_variables.grep(/six/)
13569 * # => [:$six]
13570 * local_variables
13571 * # => [:seven]
13572 *
13573 * A +Symbol+ object differs from a String object in that
13574 * a +Symbol+ object represents an identifier, while a String object
13575 * represents text or data.
13576 *
13577 * == What's Here
13578 *
13579 * First, what's elsewhere. Class +Symbol+:
13580 *
13581 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
13582 * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
13583 *
13584 * Here, class +Symbol+ provides methods that are useful for:
13585 *
13586 * - {Querying}[rdoc-ref:Symbol@Methods+for+Querying]
13587 * - {Comparing}[rdoc-ref:Symbol@Methods+for+Comparing]
13588 * - {Converting}[rdoc-ref:Symbol@Methods+for+Converting]
13589 *
13590 * === Methods for Querying
13591 *
13592 * - ::all_symbols: Returns an array of the symbols currently in Ruby's symbol table.
13593 * - #=~: Returns the index of the first substring in symbol that matches a
13594 * given Regexp or other object; returns +nil+ if no match is found.
13595 * - #[], #slice : Returns a substring of symbol
13596 * determined by a given index, start/length, or range, or string.
13597 * - #empty?: Returns +true+ if +self.length+ is zero; +false+ otherwise.
13598 * - #encoding: Returns the Encoding object that represents the encoding
13599 * of symbol.
13600 * - #end_with?: Returns +true+ if symbol ends with
13601 * any of the given strings.
13602 * - #match: Returns a MatchData object if symbol
13603 * matches a given Regexp; +nil+ otherwise.
13604 * - #match?: Returns +true+ if symbol
13605 * matches a given Regexp; +false+ otherwise.
13606 * - #length, #size: Returns the number of characters in symbol.
13607 * - #start_with?: Returns +true+ if symbol starts with
13608 * any of the given strings.
13609 *
13610 * === Methods for Comparing
13611 *
13612 * - #<=>: Returns -1, 0, or 1 as a given symbol is smaller than, equal to,
13613 * or larger than symbol.
13614 * - #==, #===: Returns +true+ if a given symbol has the same content and
13615 * encoding.
13616 * - #casecmp: Ignoring case, returns -1, 0, or 1 as a given
13617 * symbol is smaller than, equal to, or larger than symbol.
13618 * - #casecmp?: Returns +true+ if symbol is equal to a given symbol
13619 * after Unicode case folding; +false+ otherwise.
13620 *
13621 * === Methods for Converting
13622 *
13623 * - #capitalize: Returns symbol with the first character upcased
13624 * and all other characters downcased.
13625 * - #downcase: Returns symbol with all characters downcased.
13626 * - #inspect: Returns the string representation of +self+ as a symbol literal.
13627 * - #name: Returns the frozen string corresponding to symbol.
13628 * - #succ, #next: Returns the symbol that is the successor to symbol.
13629 * - #swapcase: Returns symbol with all upcase characters downcased
13630 * and all downcase characters upcased.
13631 * - #to_proc: Returns a Proc object which responds to the method named by symbol.
13632 * - #to_s, #id2name: Returns the string corresponding to +self+.
13633 * - #to_sym, #intern: Returns +self+.
13634 * - #upcase: Returns symbol with all characters upcased.
13635 *
13636 */
13637
13638
13639/*
13640 * call-seq:
13641 * self == other -> true or false
13642 *
13643 * Returns whether +other+ is the same object as +self+.
13644 */
13645
13646#define sym_equal rb_obj_equal
13647
13648static int
13649sym_printable(const char *s, const char *send, rb_encoding *enc)
13650{
13651 while (s < send) {
13652 int n;
13653 int c = rb_enc_precise_mbclen(s, send, enc);
13654
13655 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
13656 n = MBCLEN_CHARFOUND_LEN(c);
13657 c = rb_enc_mbc_to_codepoint(s, send, enc);
13658 if (!rb_enc_isprint(c, enc)) return FALSE;
13659 s += n;
13660 }
13661 return TRUE;
13662}
13663
13664int
13665rb_str_symname_p(VALUE sym)
13666{
13667 rb_encoding *enc;
13668 const char *ptr;
13669 long len;
13670 rb_encoding *resenc = rb_default_internal_encoding();
13671
13672 if (resenc == NULL) resenc = rb_default_external_encoding();
13673 enc = STR_ENC_GET(sym);
13674 ptr = RSTRING_PTR(sym);
13675 len = RSTRING_LEN(sym);
13676 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) || len != (long)strlen(ptr) ||
13677 !rb_enc_symname2_p(ptr, len, enc) || !sym_printable(ptr, ptr + len, enc)) {
13678 return FALSE;
13679 }
13680 return TRUE;
13681}
13682
13683VALUE
13684rb_str_quote_unprintable(VALUE str)
13685{
13686 rb_encoding *enc;
13687 const char *ptr;
13688 long len;
13689 rb_encoding *resenc;
13690
13691 Check_Type(str, T_STRING);
13692 resenc = rb_default_internal_encoding();
13693 if (resenc == NULL) resenc = rb_default_external_encoding();
13694 enc = STR_ENC_GET(str);
13695 ptr = RSTRING_PTR(str);
13696 len = RSTRING_LEN(str);
13697 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13698 !sym_printable(ptr, ptr + len, enc)) {
13699 return rb_str_escape(str);
13700 }
13701 return str;
13702}
13703
13704VALUE
13705rb_id_quote_unprintable(ID id)
13706{
13707 VALUE str = rb_id2str(id);
13708 if (!rb_str_symname_p(str)) {
13709 return rb_str_escape(str);
13710 }
13711 return str;
13712}
13713
13714/*
13715 * call-seq:
13716 * inspect -> string
13717 *
13718 * Returns a string representation of +self+ (including the leading colon):
13719 *
13720 * :foo.inspect # => ":foo"
13721 *
13722 * Related: Symbol#to_s, Symbol#name.
13723 *
13724 */
13725
13726static VALUE
13727sym_inspect(VALUE sym)
13728{
13729 VALUE str = rb_sym2str(sym);
13730 const char *ptr;
13731 long len;
13732 char *dest;
13733
13734 if (!rb_str_symname_p(str)) {
13735 str = rb_str_inspect(str);
13736 len = RSTRING_LEN(str);
13737 rb_str_resize(str, len + 1);
13738 dest = RSTRING_PTR(str);
13739 memmove(dest + 1, dest, len);
13740 }
13741 else {
13742 rb_encoding *enc = STR_ENC_GET(str);
13743 VALUE orig_str = str;
13744
13745 len = RSTRING_LEN(orig_str);
13746 str = rb_enc_str_new(0, len + 1, enc);
13747
13748 // Get data pointer after allocation
13749 ptr = RSTRING_PTR(orig_str);
13750 dest = RSTRING_PTR(str);
13751 memcpy(dest + 1, ptr, len);
13752
13753 RB_GC_GUARD(orig_str);
13754 }
13755 dest[0] = ':';
13756
13758
13759 return str;
13760}
13761
13762VALUE
13764{
13765 return rb_sym2str(sym);
13766}
13767
13768VALUE
13769rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc)
13770{
13771 VALUE obj;
13772
13773 if (argc < 1) {
13774 rb_raise(rb_eArgError, "no receiver given");
13775 }
13776 obj = argv[0];
13777 return rb_funcall_with_block_kw(obj, mid, argc - 1, argv + 1, passed_proc, kw_splat);
13778}
13779
13780/*
13781 * call-seq:
13782 * succ
13783 *
13784 * Equivalent to <tt>self.to_s.succ.to_sym</tt>:
13785 *
13786 * :foo.succ # => :fop
13787 *
13788 * Related: String#succ.
13789 */
13790
13791static VALUE
13792sym_succ(VALUE sym)
13793{
13794 return rb_str_intern(rb_str_succ(rb_sym2str(sym)));
13795}
13796
13797/*
13798 * call-seq:
13799 * self <=> other -> -1, 0, 1, or nil
13800 *
13801 * Compares +self+ and +other+, using String#<=>.
13802 *
13803 * Returns:
13804 *
13805 * - <tt>self.to_s <=> other.to_s</tt>, if +other+ is a symbol.
13806 * - +nil+, otherwise.
13807 *
13808 * Examples:
13809 *
13810 * :bar <=> :foo # => -1
13811 * :foo <=> :foo # => 0
13812 * :foo <=> :bar # => 1
13813 * :foo <=> 'bar' # => nil
13814 *
13815 * \Class \Symbol includes module Comparable,
13816 * each of whose methods uses Symbol#<=> for comparison.
13817 *
13818 * Related: String#<=>.
13819 */
13820
13821static VALUE
13822sym_cmp(VALUE sym, VALUE other)
13823{
13824 if (!SYMBOL_P(other)) {
13825 return Qnil;
13826 }
13827 return rb_str_cmp_m(rb_sym2str(sym), rb_sym2str(other));
13828}
13829
13830/*
13831 * call-seq:
13832 * casecmp(object) -> -1, 0, 1, or nil
13833 *
13834 * :include: doc/symbol/casecmp.rdoc
13835 *
13836 */
13837
13838static VALUE
13839sym_casecmp(VALUE sym, VALUE other)
13840{
13841 if (!SYMBOL_P(other)) {
13842 return Qnil;
13843 }
13844 return str_casecmp(rb_sym2str(sym), rb_sym2str(other));
13845}
13846
13847/*
13848 * call-seq:
13849 * casecmp?(object) -> true, false, or nil
13850 *
13851 * :include: doc/symbol/casecmp_p.rdoc
13852 *
13853 */
13854
13855static VALUE
13856sym_casecmp_p(VALUE sym, VALUE other)
13857{
13858 if (!SYMBOL_P(other)) {
13859 return Qnil;
13860 }
13861 return str_casecmp_p(rb_sym2str(sym), rb_sym2str(other));
13862}
13863
13864/*
13865 * call-seq:
13866 * self =~ other -> integer or nil
13867 *
13868 * Equivalent to <tt>self.to_s =~ other</tt>,
13869 * including possible updates to global variables;
13870 * see String#=~.
13871 *
13872 */
13873
13874static VALUE
13875sym_match(VALUE sym, VALUE other)
13876{
13877 return rb_str_match(rb_sym2str(sym), other);
13878}
13879
13880/*
13881 * call-seq:
13882 * match(pattern, offset = 0) -> matchdata or nil
13883 * match(pattern, offset = 0) {|matchdata| } -> object
13884 *
13885 * Equivalent to <tt>self.to_s.match</tt>,
13886 * including possible updates to global variables;
13887 * see String#match.
13888 *
13889 */
13890
13891static VALUE
13892sym_match_m(int argc, VALUE *argv, VALUE sym)
13893{
13894 return rb_str_match_m(argc, argv, rb_sym2str(sym));
13895}
13896
13897/*
13898 * call-seq:
13899 * match?(pattern, offset) -> true or false
13900 *
13901 * Equivalent to <tt>sym.to_s.match?</tt>;
13902 * see String#match.
13903 *
13904 */
13905
13906static VALUE
13907sym_match_m_p(int argc, VALUE *argv, VALUE sym)
13908{
13909 return rb_str_match_m_p(argc, argv, sym);
13910}
13911
13912/*
13913 * call-seq:
13914 * self[offset] -> string or nil
13915 * self[offset, size] -> string or nil
13916 * self[range] -> string or nil
13917 * self[regexp, capture = 0] -> string or nil
13918 * self[substring] -> string or nil
13919 *
13920 * Equivalent to <tt>symbol.to_s[]</tt>; see String#[].
13921 *
13922 */
13923
13924static VALUE
13925sym_aref(int argc, VALUE *argv, VALUE sym)
13926{
13927 return rb_str_aref_m(argc, argv, rb_sym2str(sym));
13928}
13929
13930/*
13931 * call-seq:
13932 * length -> integer
13933 *
13934 * Equivalent to <tt>self.to_s.length</tt>; see String#length.
13935 */
13936
13937static VALUE
13938sym_length(VALUE sym)
13939{
13940 return rb_str_length(rb_sym2str(sym));
13941}
13942
13943/*
13944 * call-seq:
13945 * upcase(mapping) -> symbol
13946 *
13947 * Equivalent to <tt>sym.to_s.upcase.to_sym</tt>.
13948 *
13949 * See String#upcase.
13950 *
13951 */
13952
13953static VALUE
13954sym_upcase(int argc, VALUE *argv, VALUE sym)
13955{
13956 return rb_str_intern(rb_str_upcase(argc, argv, rb_sym2str(sym)));
13957}
13958
13959/*
13960 * call-seq:
13961 * downcase(mapping) -> symbol
13962 *
13963 * Equivalent to <tt>sym.to_s.downcase.to_sym</tt>.
13964 *
13965 * See String#downcase.
13966 *
13967 * Related: Symbol#upcase.
13968 *
13969 */
13970
13971static VALUE
13972sym_downcase(int argc, VALUE *argv, VALUE sym)
13973{
13974 return rb_str_intern(rb_str_downcase(argc, argv, rb_sym2str(sym)));
13975}
13976
13977/*
13978 * call-seq:
13979 * capitalize(mapping) -> symbol
13980 *
13981 * Equivalent to <tt>sym.to_s.capitalize.to_sym</tt>.
13982 *
13983 * See String#capitalize.
13984 *
13985 */
13986
13987static VALUE
13988sym_capitalize(int argc, VALUE *argv, VALUE sym)
13989{
13990 return rb_str_intern(rb_str_capitalize(argc, argv, rb_sym2str(sym)));
13991}
13992
13993/*
13994 * call-seq:
13995 * swapcase(mapping) -> symbol
13996 *
13997 * Equivalent to <tt>sym.to_s.swapcase.to_sym</tt>.
13998 *
13999 * See String#swapcase.
14000 *
14001 */
14002
14003static VALUE
14004sym_swapcase(int argc, VALUE *argv, VALUE sym)
14005{
14006 return rb_str_intern(rb_str_swapcase(argc, argv, rb_sym2str(sym)));
14007}
14008
14009/*
14010 * call-seq:
14011 * start_with?(*string_or_regexp) -> true or false
14012 *
14013 * Equivalent to <tt>self.to_s.start_with?</tt>; see String#start_with?.
14014 *
14015 */
14016
14017static VALUE
14018sym_start_with(int argc, VALUE *argv, VALUE sym)
14019{
14020 return rb_str_start_with(argc, argv, rb_sym2str(sym));
14021}
14022
14023/*
14024 * call-seq:
14025 * end_with?(*strings) -> true or false
14026 *
14027 *
14028 * Equivalent to <tt>self.to_s.end_with?</tt>; see String#end_with?.
14029 *
14030 */
14031
14032static VALUE
14033sym_end_with(int argc, VALUE *argv, VALUE sym)
14034{
14035 return rb_str_end_with(argc, argv, rb_sym2str(sym));
14036}
14037
14038/*
14039 * call-seq:
14040 * encoding -> encoding
14041 *
14042 * Equivalent to <tt>self.to_s.encoding</tt>; see String#encoding.
14043 *
14044 */
14045
14046static VALUE
14047sym_encoding(VALUE sym)
14048{
14049 return rb_obj_encoding(rb_sym2str(sym));
14050}
14051
14052static VALUE
14053string_for_symbol(VALUE name)
14054{
14055 if (!RB_TYPE_P(name, T_STRING)) {
14056 VALUE tmp = rb_check_string_type(name);
14057 if (NIL_P(tmp)) {
14058 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
14059 name);
14060 }
14061 name = tmp;
14062 }
14063 return name;
14064}
14065
14066ID
14068{
14069 if (SYMBOL_P(name)) {
14070 return SYM2ID(name);
14071 }
14072 name = string_for_symbol(name);
14073 return rb_intern_str(name);
14074}
14075
14076VALUE
14078{
14079 if (SYMBOL_P(name)) {
14080 return name;
14081 }
14082 name = string_for_symbol(name);
14083 return rb_str_intern(name);
14084}
14085
14086/*
14087 * call-seq:
14088 * Symbol.all_symbols -> array_of_symbols
14089 *
14090 * Returns an array of all symbols currently in Ruby's symbol table:
14091 *
14092 * Symbol.all_symbols.size # => 9334
14093 * Symbol.all_symbols.take(3) # => [:!, :"\"", :"#"]
14094 *
14095 */
14096
14097static VALUE
14098sym_all_symbols(VALUE _)
14099{
14100 return rb_sym_all_symbols();
14101}
14102
14103VALUE
14104rb_str_to_interned_str(VALUE str)
14105{
14106 return rb_fstring(str);
14107}
14108
14109VALUE
14110rb_interned_str(const char *ptr, long len)
14111{
14112 struct RString fake_str = {RBASIC_INIT};
14113 int encidx = ENCINDEX_US_ASCII;
14114 int coderange = ENC_CODERANGE_7BIT;
14115 if (len > 0 && search_nonascii(ptr, ptr + len)) {
14116 encidx = ENCINDEX_ASCII_8BIT;
14117 coderange = ENC_CODERANGE_VALID;
14118 }
14119 VALUE str = setup_fake_str(&fake_str, ptr, len, encidx);
14120 ENC_CODERANGE_SET(str, coderange);
14121 return register_fstring(str, true, false);
14122}
14123
14124VALUE
14126{
14127 return rb_interned_str(ptr, strlen(ptr));
14128}
14129
14130VALUE
14131rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
14132{
14133 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14134 rb_enc_autoload(enc);
14135 }
14136
14137 struct RString fake_str = {RBASIC_INIT};
14138 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, false);
14139}
14140
14141VALUE
14142rb_enc_literal_str(const char *ptr, long len, rb_encoding *enc)
14143{
14144 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14145 rb_enc_autoload(enc);
14146 }
14147
14148 struct RString fake_str = {RBASIC_INIT};
14149 VALUE str = register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true);
14150 RUBY_ASSERT(RB_OBJ_SHAREABLE_P(str) && (rb_gc_verify_shareable(str), 1));
14151 return str;
14152}
14153
14154VALUE
14156{
14157 return rb_enc_interned_str(ptr, strlen(ptr), enc);
14158}
14159
14160#if USE_YJIT || USE_ZJIT
14161void
14162rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint)
14163{
14164 if (RB_LIKELY(ENCODING_GET_INLINED(str) == rb_ascii8bit_encindex())) {
14165 ssize_t code = RB_NUM2SSIZE(codepoint);
14166
14167 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14168 rb_str_buf_cat_byte(str, (char) code);
14169 return;
14170 }
14171 }
14172
14173 rb_str_concat(str, codepoint);
14174}
14175#endif
14176
14177static int
14178fstring_set_class_i(VALUE *str, void *data)
14179{
14180 RBASIC_SET_CLASS(*str, rb_cString);
14181
14182 return ST_CONTINUE;
14183}
14184
14185void
14186Init_String(void)
14187{
14188 rb_cString = rb_define_class("String", rb_cObject);
14189
14190 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14191
14193 rb_define_alloc_func(rb_cString, empty_str_alloc);
14194 rb_define_singleton_method(rb_cString, "new", rb_str_s_new, -1);
14195 rb_define_singleton_method(rb_cString, "try_convert", rb_str_s_try_convert, 1);
14196 rb_define_method(rb_cString, "initialize", rb_str_init, -1);
14198 rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1);
14199 rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
14202 rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
14203 rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
14204 rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
14205 rb_define_method(rb_cString, "casecmp?", rb_str_casecmp_p, 1);
14208 rb_define_method(rb_cString, "%", rb_str_format_m, 1);
14209 rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
14210 rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
14211 rb_define_method(rb_cString, "insert", rb_str_insert, 2);
14214 rb_define_method(rb_cString, "bytesize", rb_str_bytesize, 0);
14215 rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
14216 rb_define_method(rb_cString, "=~", rb_str_match, 1);
14217 rb_define_method(rb_cString, "match", rb_str_match_m, -1);
14218 rb_define_method(rb_cString, "match?", rb_str_match_m_p, -1);
14220 rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0);
14222 rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0);
14223 rb_define_method(rb_cString, "upto", rb_str_upto, -1);
14224 rb_define_method(rb_cString, "index", rb_str_index_m, -1);
14225 rb_define_method(rb_cString, "byteindex", rb_str_byteindex_m, -1);
14226 rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1);
14227 rb_define_method(rb_cString, "byterindex", rb_str_byterindex_m, -1);
14228 rb_define_method(rb_cString, "clear", rb_str_clear, 0);
14229 rb_define_method(rb_cString, "chr", rb_str_chr, 0);
14230 rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
14231 rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);
14232 rb_define_method(rb_cString, "bit_get", rb_str_bit_get, -1);
14233 rb_define_method(rb_cString, "bit_set?", rb_str_bit_set_p, -1);
14234 rb_define_method(rb_cString, "bit_set", rb_str_bit_set, -1);
14235 rb_define_method(rb_cString, "bit_clear", rb_str_bit_clear, -1);
14236 rb_define_method(rb_cString, "bit_flip", rb_str_bit_flip, -1);
14237 rb_define_method(rb_cString, "bit_count", rb_str_bit_count, -1);
14238 rb_define_method(rb_cString, "bitwise_not", rb_str_bitwise_not, 0);
14239 rb_define_method(rb_cString, "bitwise_not!", rb_str_bitwise_not_bang, 0);
14240 rb_define_method(rb_cString, "bitwise_and", rb_str_bitwise_and, 1);
14241 rb_define_method(rb_cString, "bitwise_and!", rb_str_bitwise_and_bang, 1);
14242 rb_define_method(rb_cString, "bitwise_or", rb_str_bitwise_or, 1);
14243 rb_define_method(rb_cString, "bitwise_or!", rb_str_bitwise_or_bang, 1);
14244 rb_define_method(rb_cString, "bitwise_xor", rb_str_bitwise_xor, 1);
14245 rb_define_method(rb_cString, "bitwise_xor!", rb_str_bitwise_xor_bang, 1);
14246 rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);
14247 rb_define_method(rb_cString, "bytesplice", rb_str_bytesplice, -1);
14248 rb_define_method(rb_cString, "scrub", str_scrub, -1);
14249 rb_define_method(rb_cString, "scrub!", str_scrub_bang, -1);
14251 rb_define_method(rb_cString, "+@", str_uplus, 0);
14252 rb_define_method(rb_cString, "-@", str_uminus, 0);
14253 rb_define_method(rb_cString, "dup", rb_str_dup_m, 0);
14254 rb_define_alias(rb_cString, "dedup", "-@");
14255
14256 rb_define_method(rb_cString, "to_i", rb_str_to_i, -1);
14257 rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);
14258 rb_define_method(rb_cString, "to_s", rb_str_to_s, 0);
14259 rb_define_method(rb_cString, "to_str", rb_str_to_s, 0);
14262 rb_define_method(rb_cString, "undump", str_undump, 0);
14263
14264 sym_ascii = ID2SYM(rb_intern_const("ascii"));
14265 sym_turkic = ID2SYM(rb_intern_const("turkic"));
14266 sym_lithuanian = ID2SYM(rb_intern_const("lithuanian"));
14267 sym_fold = ID2SYM(rb_intern_const("fold"));
14268
14269 rb_define_method(rb_cString, "upcase", rb_str_upcase, -1);
14270 rb_define_method(rb_cString, "downcase", rb_str_downcase, -1);
14271 rb_define_method(rb_cString, "capitalize", rb_str_capitalize, -1);
14272 rb_define_method(rb_cString, "swapcase", rb_str_swapcase, -1);
14273
14274 rb_define_method(rb_cString, "upcase!", rb_str_upcase_bang, -1);
14275 rb_define_method(rb_cString, "downcase!", rb_str_downcase_bang, -1);
14276 rb_define_method(rb_cString, "capitalize!", rb_str_capitalize_bang, -1);
14277 rb_define_method(rb_cString, "swapcase!", rb_str_swapcase_bang, -1);
14278
14279 rb_define_method(rb_cString, "hex", rb_str_hex, 0);
14280 rb_define_method(rb_cString, "oct", rb_str_oct, 0);
14281 rb_define_method(rb_cString, "split", rb_str_split_m, -1);
14282 rb_define_method(rb_cString, "lines", rb_str_lines, -1);
14283 rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
14284 rb_define_method(rb_cString, "chars", rb_str_chars, 0);
14285 rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
14286 rb_define_method(rb_cString, "grapheme_clusters", rb_str_grapheme_clusters, 0);
14287 rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
14288 rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
14289 rb_define_method(rb_cString, "concat", rb_str_concat_multi, -1);
14290 rb_define_method(rb_cString, "append_as_bytes", rb_str_append_as_bytes, -1);
14292 rb_define_method(rb_cString, "prepend", rb_str_prepend_multi, -1);
14293 rb_define_method(rb_cString, "crypt", rb_str_crypt, 1);
14294 rb_define_method(rb_cString, "intern", rb_str_intern, 0); /* in symbol.c */
14295 rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); /* in symbol.c */
14296 rb_define_method(rb_cString, "ord", rb_str_ord, 0);
14297
14298 rb_define_method(rb_cString, "include?", rb_str_include, 1);
14299 rb_define_method(rb_cString, "start_with?", rb_str_start_with, -1);
14300 rb_define_method(rb_cString, "end_with?", rb_str_end_with, -1);
14301
14302 rb_define_method(rb_cString, "scan", rb_str_scan, 1);
14303
14304 rb_define_method(rb_cString, "ljust", rb_str_ljust, -1);
14305 rb_define_method(rb_cString, "rjust", rb_str_rjust, -1);
14306 rb_define_method(rb_cString, "center", rb_str_center, -1);
14307
14308 rb_define_method(rb_cString, "sub", rb_str_sub, -1);
14309 rb_define_method(rb_cString, "gsub", rb_str_gsub, -1);
14310 rb_define_method(rb_cString, "chop", rb_str_chop, 0);
14311 rb_define_method(rb_cString, "chomp", rb_str_chomp, -1);
14312 rb_define_method(rb_cString, "strip", rb_str_strip, -1);
14313 rb_define_method(rb_cString, "lstrip", rb_str_lstrip, -1);
14314 rb_define_method(rb_cString, "rstrip", rb_str_rstrip, -1);
14315 rb_define_method(rb_cString, "delete_prefix", rb_str_delete_prefix, 1);
14316 rb_define_method(rb_cString, "delete_suffix", rb_str_delete_suffix, 1);
14317
14318 rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1);
14319 rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1);
14320 rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0);
14321 rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1);
14322 rb_define_method(rb_cString, "strip!", rb_str_strip_bang, -1);
14323 rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, -1);
14324 rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, -1);
14325 rb_define_method(rb_cString, "delete_prefix!", rb_str_delete_prefix_bang, 1);
14326 rb_define_method(rb_cString, "delete_suffix!", rb_str_delete_suffix_bang, 1);
14327
14328 rb_define_method(rb_cString, "tr", rb_str_tr, -1);
14329 rb_define_method(rb_cString, "tr_s", rb_str_tr_s, 2);
14330 rb_define_method(rb_cString, "delete", rb_str_delete, -1);
14331 rb_define_method(rb_cString, "squeeze", rb_str_squeeze, -1);
14332 rb_define_method(rb_cString, "count", rb_str_count, -1);
14333
14334 rb_define_method(rb_cString, "tr!", rb_str_tr_bang, -1);
14335 rb_define_method(rb_cString, "tr_s!", rb_str_tr_s_bang, 2);
14336 rb_define_method(rb_cString, "delete!", rb_str_delete_bang, -1);
14337 rb_define_method(rb_cString, "squeeze!", rb_str_squeeze_bang, -1);
14338
14339 rb_define_method(rb_cString, "each_line", rb_str_each_line, -1);
14340 rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0);
14341 rb_define_method(rb_cString, "each_char", rb_str_each_char, 0);
14342 rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0);
14343 rb_define_method(rb_cString, "each_grapheme_cluster", rb_str_each_grapheme_cluster, 0);
14344
14345 rb_define_method(rb_cString, "sum", rb_str_sum, -1);
14346
14347 rb_define_method(rb_cString, "slice", rb_str_aref_m, -1);
14348 rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1);
14349
14350 rb_define_method(rb_cString, "partition", rb_str_partition, 1);
14351 rb_define_method(rb_cString, "rpartition", rb_str_rpartition, 1);
14352
14353 rb_define_method(rb_cString, "encoding", rb_obj_encoding, 0); /* in encoding.c */
14354 rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1);
14355 rb_define_method(rb_cString, "b", rb_str_b, 0);
14356
14357 /* define UnicodeNormalize module here so that we don't have to look it up */
14358 mUnicodeNormalize = rb_define_module("UnicodeNormalize");
14359 id_normalize = rb_intern_const("normalize");
14360 id_normalized_p = rb_intern_const("normalized?");
14361
14362 rb_define_method(rb_cString, "unicode_normalize", rb_str_unicode_normalize, -1);
14363 rb_define_method(rb_cString, "unicode_normalize!", rb_str_unicode_normalize_bang, -1);
14364 rb_define_method(rb_cString, "unicode_normalized?", rb_str_unicode_normalized_p, -1);
14365
14366 rb_fs = Qnil;
14367 rb_define_hooked_variable("$;", &rb_fs, 0, rb_fs_setter);
14368 rb_define_hooked_variable("$-F", &rb_fs, 0, rb_fs_setter);
14369 rb_gc_register_address(&rb_fs);
14370
14371 rb_cSymbol = rb_define_class("Symbol", rb_cObject);
14375 rb_define_singleton_method(rb_cSymbol, "all_symbols", sym_all_symbols, 0);
14376
14377 rb_define_method(rb_cSymbol, "==", sym_equal, 1);
14378 rb_define_method(rb_cSymbol, "===", sym_equal, 1);
14379 rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
14380 rb_define_method(rb_cSymbol, "to_proc", rb_sym_to_proc, 0); /* in proc.c */
14381 rb_define_method(rb_cSymbol, "succ", sym_succ, 0);
14382 rb_define_method(rb_cSymbol, "next", sym_succ, 0);
14383
14384 rb_define_method(rb_cSymbol, "<=>", sym_cmp, 1);
14385 rb_define_method(rb_cSymbol, "casecmp", sym_casecmp, 1);
14386 rb_define_method(rb_cSymbol, "casecmp?", sym_casecmp_p, 1);
14387 rb_define_method(rb_cSymbol, "=~", sym_match, 1);
14388
14389 rb_define_method(rb_cSymbol, "[]", sym_aref, -1);
14390 rb_define_method(rb_cSymbol, "slice", sym_aref, -1);
14391 rb_define_method(rb_cSymbol, "length", sym_length, 0);
14392 rb_define_method(rb_cSymbol, "size", sym_length, 0);
14393 rb_define_method(rb_cSymbol, "match", sym_match_m, -1);
14394 rb_define_method(rb_cSymbol, "match?", sym_match_m_p, -1);
14395
14396 rb_define_method(rb_cSymbol, "upcase", sym_upcase, -1);
14397 rb_define_method(rb_cSymbol, "downcase", sym_downcase, -1);
14398 rb_define_method(rb_cSymbol, "capitalize", sym_capitalize, -1);
14399 rb_define_method(rb_cSymbol, "swapcase", sym_swapcase, -1);
14400
14401 rb_define_method(rb_cSymbol, "start_with?", sym_start_with, -1);
14402 rb_define_method(rb_cSymbol, "end_with?", sym_end_with, -1);
14403
14404 rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0);
14405}
14406
14407#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:1764
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3082
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2892
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:3372
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1034
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3161
#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:677
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4074
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1467
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1463
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
Definition error.c:1470
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1461
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1465
@ 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:2256
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:2274
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:3646
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_cRange
Range class.
Definition range.c:35
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:140
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:905
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:3332
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:14131
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:14155
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:213
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
Definition vm.c:2111
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:2117
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1882
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:13763
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:5441
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:13078
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:6652
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:14125
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:8124
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:14110
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:5928
VALUE rb_str_scrub(VALUE str, VALUE repl)
"Cleanses" the string.
Definition string.c:13136
#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:8241
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:5843
VALUE rb_str_split(VALUE str, const char *delim)
Divides the given string based on the given delimiter.
Definition string.c:10769
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:2102
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
Definition variable.c:2162
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3647
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1843
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:14077
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:14067
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_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
Definition ractor.h:290
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:255
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:1528
#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:9165
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Blocks until the current thread obtains a lock.
Definition thread.c:319
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