Ruby 4.1.0dev (2026-10-14 revision d71692d49f30e60296bd57c932eb8877e83c3b4d)
string.c (d71692d49f30e60296bd57c932eb8877e83c3b4d)
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 rb_len_t 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, rb_len_t beg, rb_len_t len)
213{
214#if SHARABLE_MIDDLE_SUBSTRING
215 return true;
216#else
217 rb_len_t end = beg + len;
218 rb_len_t 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 rb_len_t
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(rb_len_t capa, rb_len_t 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(rb_len_t len, rb_len_t 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, rb_len_t len, int encindex);
292static VALUE str_new(VALUE klass, const char *ptr, rb_len_t len);
293static void str_make_independent_expand(VALUE str, rb_len_t len, rb_len_t 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 rb_len_t 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 rb_len_t old_capa = RSTRING(str)->as.heap.aux.capa + termlen;
325 rb_len_t 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_RB_LEN_T == 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 rb_len_t 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 rb_len_t len = RSTRING_LEN(str);
509 rb_len_t 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#ifdef PRECOMPUTED_FAKESTR_HASH
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 = (rb_len_t)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, rb_len_t 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, rb_len_t 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, rb_len_t 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, rb_len_t 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, rb_len_t 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
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, rb_len_t 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, rb_len_t 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, rb_len_t len)
1122{
1123 return str_enc_new(klass, ptr, len, rb_ascii8bit_encoding());
1124}
1125
1126VALUE
1128{
1129 return str_new(rb_cString, ptr, len);
1130}
1131
1132VALUE
1134{
1135 return str_enc_new(rb_cString, ptr, len, rb_usascii_encoding());
1136}
1137
1138VALUE
1140{
1141 return str_enc_new(rb_cString, ptr, len, rb_utf8_encoding());
1142}
1143
1144VALUE
1145rb_enc_str_new(const char *ptr, rb_len_t 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, rb_len_t 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
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, rb_len_t len, rb_len_t 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, rb_len_t ofs, const char *ptr, rb_len_t 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 rb_len_t 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, rb_len_t ofs, const char *ptr, rb_len_t len,
1293 rb_encoding *from, int ecflags, VALUE ecopts)
1294{
1295 rb_len_t olen;
1296
1297 olen = RSTRING_LEN(newstr);
1298 if (ofs < -olen || olen < ofs)
1299 rb_raise(rb_eIndexError, "index %"PRIdLEN" 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, rb_len_t 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, rb_len_t ofs, const char *ptr, rb_len_t len,
1323 rb_encoding *from, rb_encoding *to,
1324 int ecflags, VALUE ecopts)
1325{
1326 rb_econv_t *ec;
1328 rb_len_t 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 < (RB_LEN_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
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
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 rb_len_t 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
1585{
1586 if (OBJ_FROZEN_RAW(orig) && !STR_EMBED_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 /* str was just allocated here, so orig is its only child and it is
1612 * safe for rb_str_tmp_frozen_release to give the buffer back. */
1613 FL_UNSET_RAW(str, STR_BORROWED);
1614 if (RB_OBJ_SHAREABLE_P(orig)) {
1616 RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
1617 }
1618 }
1619
1620 RSTRING(str)->len = RSTRING(orig)->len;
1621 RSTRING(str)->as.heap.aux.capa = capa + (TERM_LEN(orig) - TERM_LEN(str));
1622
1623 return str;
1624}
1625
1626void
1628{
1629 rb_str_tmp_frozen_release(orig, tmp);
1630}
1631
1632void
1633rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
1634{
1635 if (RBASIC_CLASS(tmp) != 0)
1636 return;
1637
1638 if (STR_EMBED_P(tmp)) {
1640 }
1641 else if (FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_SHARED &&
1642 !OBJ_FROZEN_RAW(orig)) {
1643 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1644
1645 if (shared == tmp && !FL_TEST_RAW(tmp, STR_BORROWED)) {
1646 RUBY_ASSERT(RSTRING(orig)->as.heap.ptr == RSTRING(tmp)->as.heap.ptr);
1647 RUBY_ASSERT(RSTRING_LEN(orig) == RSTRING_LEN(tmp));
1648
1649 /* Unshare orig since the root (tmp) only has this one child. */
1650 FL_UNSET_RAW(orig, STR_SHARED);
1651 RSTRING(orig)->as.heap.aux.capa = RSTRING(tmp)->as.heap.aux.capa + TERM_LEN(tmp) - TERM_LEN(orig);
1652 RBASIC(orig)->flags |= RBASIC(tmp)->flags & STR_NOFREE;
1654
1655 /* Make tmp embedded and empty so it is safe for sweeping. */
1656 STR_SET_EMBED(tmp);
1657 STR_SET_LEN(tmp, 0);
1658 }
1659 }
1660}
1661
1662static VALUE
1663str_new_frozen(VALUE klass, VALUE orig)
1664{
1665 return str_new_frozen_buffer(klass, orig, TRUE);
1666}
1667
1668/* Transfers ownership of orig's buffer to a new shared root string.
1669 * termlen is the terminator length of the returned string, which may differ
1670 * from orig's terminator length when the caller does not copy the encoding.
1671 * The capacity is stored without the terminator, so it must be adjusted for
1672 * the difference to keep the buffer size (capa + termlen) unchanged. */
1673static VALUE
1674heap_str_make_shared(VALUE klass, VALUE orig, int termlen)
1675{
1676 RUBY_ASSERT(!STR_EMBED_P(orig));
1677 RUBY_ASSERT(!STR_SHARED_P(orig));
1679
1680 VALUE str = str_alloc_heap(klass);
1681 STR_SET_LEN(str, RSTRING_LEN(orig));
1682 RSTRING(str)->as.heap.ptr = RSTRING_PTR(orig);
1683 RSTRING(str)->as.heap.aux.capa = RSTRING(orig)->as.heap.aux.capa + TERM_LEN(orig) - termlen;
1684 RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1685 RBASIC(orig)->flags &= ~STR_NOFREE;
1686 STR_SET_SHARED(orig, str);
1687 if (klass == 0)
1688 FL_UNSET_RAW(str, STR_BORROWED);
1689 return str;
1690}
1691
1692static VALUE
1693str_new_frozen_buffer(VALUE klass, VALUE orig, int copy_encoding)
1694{
1695 VALUE str;
1696
1697 rb_len_t len = RSTRING_LEN(orig);
1698 rb_encoding *enc = copy_encoding ? STR_ENC_GET(orig) : rb_ascii8bit_encoding();
1699 int termlen = copy_encoding ? TERM_LEN(orig) : 1;
1700
1701 if (STR_EMBED_P(orig) || STR_EMBEDDABLE_P(len, termlen)) {
1702 str = str_enc_new(klass, RSTRING_PTR(orig), len, enc);
1703 RUBY_ASSERT(STR_EMBED_P(str));
1704 }
1705 else {
1706 if (FL_TEST_RAW(orig, STR_SHARED)) {
1707 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1708 rb_len_t ofs = RSTRING(orig)->as.heap.ptr - RSTRING_PTR(shared);
1709 rb_len_t rest = RSTRING_LEN(shared) - ofs - RSTRING_LEN(orig);
1710 RUBY_ASSERT(ofs >= 0);
1711 RUBY_ASSERT(rest >= 0);
1712 RUBY_ASSERT(ofs + rest <= RSTRING_LEN(shared));
1714
1715 if ((ofs > 0) || (rest > 0) ||
1716 (klass != RBASIC(shared)->klass) ||
1717 ENCODING_GET(shared) != ENCODING_GET(orig)) {
1718 str = str_new_shared(klass, shared);
1719 RUBY_ASSERT(!STR_EMBED_P(str));
1720 RSTRING(str)->as.heap.ptr += ofs;
1721 STR_SET_LEN(str, RSTRING_LEN(str) - (ofs + rest));
1722 }
1723 else {
1724 if (RBASIC_CLASS(shared) == 0)
1725 FL_SET_RAW(shared, STR_BORROWED);
1726 return shared;
1727 }
1728 }
1729 else if (STR_EMBEDDABLE_P(RSTRING_LEN(orig), TERM_LEN(orig))) {
1730 str = str_alloc_embed(klass, RSTRING_LEN(orig) + TERM_LEN(orig));
1731 STR_SET_EMBED(str);
1732 memcpy(RSTRING_PTR(str), RSTRING_PTR(orig), RSTRING_LEN(orig));
1733 STR_SET_LEN(str, RSTRING_LEN(orig));
1734 ENC_CODERANGE_SET(str, ENC_CODERANGE(orig));
1735 TERM_FILL(RSTRING_END(str), TERM_LEN(orig));
1736 }
1737 else {
1738 if (RB_OBJ_SHAREABLE_P(orig)) {
1739 str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
1740 }
1741 else {
1742 str = heap_str_make_shared(klass, orig, termlen);
1743 }
1744 }
1745 }
1746
1747 if (copy_encoding) rb_enc_cr_str_exact_copy(str, orig);
1748 OBJ_FREEZE(str);
1749 return str;
1750}
1751
1752VALUE
1754{
1755 return str_enc_new(rb_obj_class(obj), ptr, len, STR_ENC_GET(obj));
1756}
1757
1758static VALUE
1759str_new_empty_String(VALUE str)
1760{
1761 VALUE v = rb_str_new(0, 0);
1762 rb_enc_copy(v, str);
1763 return v;
1764}
1765
1766#define STR_BUF_MIN_SIZE 63
1767
1768VALUE
1770{
1771 if (STR_EMBEDDABLE_P(capa, 1)) {
1772 return str_alloc_embed(rb_cString, capa + 1);
1773 }
1774
1775 VALUE str = str_alloc_heap(rb_cString);
1776
1777 RSTRING(str)->as.heap.aux.capa = capa;
1778 RSTRING(str)->as.heap.ptr = ALLOC_N(char, (size_t)capa + 1);
1779 RSTRING(str)->as.heap.ptr[0] = '\0';
1780
1781 return str;
1782}
1783
1784VALUE
1786{
1787 VALUE str;
1788 rb_len_t len = strlen(ptr);
1789
1790 str = rb_str_buf_new(len);
1791 rb_str_buf_cat(str, ptr, len);
1792
1793 return str;
1794}
1795
1796VALUE
1798{
1799 return str_new(0, 0, len);
1800}
1801
1802void
1804{
1805 if (STR_EMBED_P(str)) {
1806 RB_DEBUG_COUNTER_INC(obj_str_embed);
1807 }
1808 else if (FL_TEST(str, STR_SHARED | STR_NOFREE)) {
1809 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_SHARED));
1810 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_NOFREE));
1811 }
1812 else {
1813 RB_DEBUG_COUNTER_INC(obj_str_ptr);
1814 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
1815 }
1816}
1817
1818size_t
1819rb_str_memsize(VALUE str)
1820{
1821 if (FL_TEST(str, STR_NOEMBED|STR_SHARED|STR_NOFREE) == STR_NOEMBED) {
1822 return STR_HEAP_SIZE(str);
1823 }
1824 else {
1825 return 0;
1826 }
1827}
1828
1829VALUE
1831{
1832 return rb_convert_type_with_id(str, T_STRING, "String", idTo_str);
1833}
1834
1835static inline void str_discard(VALUE str);
1836static void str_shared_replace(VALUE str, VALUE str2);
1837
1838void
1840{
1841 if (str != str2) str_shared_replace(str, str2);
1842}
1843
1844static void
1845str_shared_replace(VALUE str, VALUE str2)
1846{
1847 rb_encoding *enc;
1848 int cr;
1849 int termlen;
1850
1851 RUBY_ASSERT(str2 != str);
1852 enc = STR_ENC_GET(str2);
1853 cr = ENC_CODERANGE(str2);
1854 str_discard(str);
1855 termlen = rb_enc_mbminlen(enc);
1856
1857 STR_SET_LEN(str, RSTRING_LEN(str2));
1858
1859 if (str_embed_capa(str) >= RSTRING_LEN(str2) + termlen) {
1860 STR_SET_EMBED(str);
1861 memcpy(RSTRING_PTR(str), RSTRING_PTR(str2), (size_t)RSTRING_LEN(str2) + termlen);
1862 }
1863 else {
1864 if (STR_EMBED_P(str2)) {
1865 RUBY_ASSERT(!FL_TEST(str2, STR_SHARED));
1866 rb_len_t len = RSTRING_LEN(str2);
1867 RUBY_ASSERT(len + termlen <= str_embed_capa(str2));
1868
1869 char *new_ptr = ALLOC_N(char, len + termlen);
1870 memcpy(new_ptr, RSTRING(str2)->as.embed.ary, len + termlen);
1871 RSTRING(str2)->as.heap.ptr = new_ptr;
1872 STR_SET_LEN(str2, len);
1873 RSTRING(str2)->as.heap.aux.capa = len;
1874 STR_SET_NOEMBED(str2);
1875 }
1876
1877 STR_SET_NOEMBED(str);
1878 FL_UNSET(str, STR_SHARED);
1879 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1880
1881 if (FL_TEST(str2, STR_SHARED)) {
1882 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1883 STR_SET_SHARED(str, shared);
1884 }
1885 else {
1886 RSTRING(str)->as.heap.aux.capa = RSTRING(str2)->as.heap.aux.capa;
1887 }
1888
1889 /* abandon str2 */
1890 STR_SET_EMBED(str2);
1891 RSTRING_PTR(str2)[0] = 0;
1892 STR_SET_LEN(str2, 0);
1893 }
1894
1895 // We used str2's termlen above so we set enc raw
1896 // to avoid adjusting it based on str1's old enc.
1897 rb_enc_raw_set(str, enc);
1898 ENC_CODERANGE_SET(str, cr);
1899}
1900
1901VALUE
1903{
1904 VALUE str;
1905
1906 if (RB_TYPE_P(obj, T_STRING)) {
1907 return obj;
1908 }
1909 str = rb_funcall(obj, idTo_s, 0);
1910 return rb_obj_as_string_result(str, obj);
1911}
1912
1913VALUE
1914rb_obj_as_string_result(VALUE str, VALUE obj)
1915{
1916 if (!RB_TYPE_P(str, T_STRING))
1917 return rb_any_to_s(obj);
1918 return str;
1919}
1920
1921static VALUE
1922str_replace(VALUE str, VALUE str2)
1923{
1924 rb_len_t len;
1925
1926 len = RSTRING_LEN(str2);
1927 if (STR_SHARED_P(str2)) {
1928 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1930 STR_SET_NOEMBED(str);
1931 STR_SET_LEN(str, len);
1932 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1933 STR_SET_SHARED(str, shared);
1934 rb_enc_cr_str_exact_copy(str, str2);
1935 }
1936 else {
1937 str_replace_shared(str, str2);
1938 }
1939
1940 return str;
1941}
1942
1943static inline VALUE
1944ec_str_alloc_embed(struct rb_execution_context_struct *ec, VALUE klass, size_t capa)
1945{
1946 size_t size = rb_str_embed_size(capa, 0);
1947 RUBY_ASSERT(size > 0);
1948 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
1949
1950 EC_NEWOBJ_OF(str, struct RString, klass, T_STRING, size, ec);
1951
1952 str->len = 0;
1953
1954 return (VALUE)str;
1955}
1956
1957static inline VALUE
1958ec_str_alloc_heap(struct rb_execution_context_struct *ec, VALUE klass)
1959{
1960 EC_NEWOBJ_OF(str, struct RString, klass, T_STRING | STR_NOEMBED, sizeof(struct RString), ec);
1961
1962 str->as.heap.aux.capa = 0;
1963 str->as.heap.ptr = NULL;
1964
1965 return (VALUE)str;
1966}
1967
1968static inline void
1969str_duplicate_setup_encoding(VALUE str, VALUE dup, VALUE flags)
1970{
1971 int encidx = 0;
1972 if ((flags & ENCODING_MASK) == (ENCODING_INLINE_MAX<<ENCODING_SHIFT)) {
1973 encidx = rb_enc_get_index(str);
1974 flags &= ~ENCODING_MASK;
1975 }
1976 FL_SET_RAW(dup, flags & ~FL_FREEZE);
1977 if (encidx) rb_enc_associate_index(dup, encidx);
1978}
1979
1980static const VALUE flag_mask = ENC_CODERANGE_MASK | ENCODING_MASK | FL_FREEZE;
1981
1982static inline void
1983str_duplicate_setup_embed(VALUE klass, VALUE str, VALUE dup)
1984{
1985 VALUE flags = FL_TEST_RAW(str, flag_mask);
1986 rb_len_t len = RSTRING_LEN(str);
1987
1988 RUBY_ASSERT(STR_EMBED_P(dup));
1989 RUBY_ASSERT(str_embed_capa(dup) >= len + TERM_LEN(str));
1990 MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + TERM_LEN(str));
1991 STR_SET_LEN(dup, RSTRING_LEN(str));
1992 str_duplicate_setup_encoding(str, dup, flags);
1993}
1994
1995static inline void
1996str_duplicate_setup_heap(VALUE klass, VALUE str, VALUE dup)
1997{
1998 VALUE flags = FL_TEST_RAW(str, flag_mask);
1999 VALUE root = str;
2000 if (FL_TEST_RAW(str, STR_SHARED)) {
2001 root = RSTRING(str)->as.heap.aux.shared;
2002 }
2003 else if (UNLIKELY(!OBJ_FROZEN_RAW(str))) {
2004 root = str = str_new_frozen(klass, str);
2005 flags = FL_TEST_RAW(str, flag_mask);
2006 }
2007 RUBY_ASSERT(!STR_SHARED_P(root));
2009
2010 RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
2011 FL_SET_RAW(dup, RSTRING_NOEMBED);
2012 STR_SET_SHARED(dup, root);
2013 flags |= RSTRING_NOEMBED | STR_SHARED;
2014
2015 STR_SET_LEN(dup, RSTRING_LEN(str));
2016 str_duplicate_setup_encoding(str, dup, flags);
2017}
2018
2019static inline VALUE
2020str_duplicate(VALUE klass, VALUE str)
2021{
2022 VALUE dup;
2023 if (STR_EMBED_P(str) && rb_str_embed_size(RSTRING_LEN(str), 1) <= STR_COPY_MAX_EMBED_SIZE) {
2024 dup = str_alloc_embed(klass, RSTRING_LEN(str) + TERM_LEN(str));
2025
2026 str_duplicate_setup_embed(klass, str, dup);
2027 }
2028 else {
2029 dup = str_alloc_heap(klass);
2030
2031 str_duplicate_setup_heap(klass, str, dup);
2032 }
2033
2034 return dup;
2035}
2036
2037VALUE
2039{
2040 return str_duplicate(rb_obj_class(str), str);
2041}
2042
2043/* :nodoc: */
2044VALUE
2045rb_str_dup_m(VALUE str)
2046{
2047 if (LIKELY(BARE_STRING_P(str))) {
2048 return str_duplicate(rb_cString, str);
2049 }
2050 else {
2051 return rb_obj_dup(str);
2052 }
2053}
2054
2055VALUE
2057{
2058 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2059 return str_duplicate(rb_cString, str);
2060}
2061
2062VALUE
2063rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled)
2064{
2065 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2066 VALUE new_str, klass = rb_cString;
2067
2068 if (!(chilled && RTEST(rb_ivar_defined(str, id_debug_created_info))) && STR_EMBED_P(str)) {
2069 new_str = ec_str_alloc_embed(ec, klass, RSTRING_LEN(str) + TERM_LEN(str));
2070 str_duplicate_setup_embed(klass, str, new_str);
2071 }
2072 else {
2073 new_str = ec_str_alloc_heap(ec, klass);
2074 str_duplicate_setup_heap(klass, str, new_str);
2075 }
2076 if (chilled) {
2077 FL_SET_RAW(new_str, STR_CHILLED);
2078 }
2079 return new_str;
2080}
2081
2082#if USE_ZJIT
2083bool
2084rb_zjit_str_resurrect_fastpath(VALUE str, bool chilled, size_t *size_out,
2085 VALUE *flags_out,
2086 rb_len_t *len_out, size_t *byte_size_out)
2087{
2088 if (chilled && RTEST(rb_ivar_defined(str, id_debug_created_info))) return false;
2089
2090 if (!STR_EMBED_P(str)) return false;
2091
2092 rb_len_t len = RSTRING_LEN(str);
2093 rb_len_t termlen = TERM_LEN(str);
2094 size_t size = rb_str_embed_size(len + termlen, 0);
2095 if (!rb_gc_size_allocatable_p(size)) return false;
2096
2097 VALUE flags = FL_TEST_RAW(str, flag_mask);
2098
2099 if ((flags & ENCODING_MASK) == ((VALUE)ENCODING_INLINE_MAX << ENCODING_SHIFT)) {
2100 return false;
2101 }
2102
2103 flags &= ~FL_FREEZE;
2104 flags |= T_STRING;
2105 if (chilled) flags |= STR_CHILLED;
2106
2107 *size_out = size;
2108 *flags_out = flags;
2109 *len_out = len;
2110 *byte_size_out = (size_t)(len + termlen);
2111 return true;
2112}
2113#endif
2114
2115VALUE
2116rb_str_with_debug_created_info(VALUE str, VALUE path, int line)
2117{
2118 VALUE debug_info = rb_ary_new_from_args(2, path, INT2FIX(line));
2119 if (OBJ_FROZEN_RAW(str)) str = rb_str_dup(str);
2120 rb_ivar_set(str, id_debug_created_info, rb_ary_freeze(debug_info));
2121 FL_SET_RAW(str, STR_CHILLED);
2122 return rb_str_freeze(str);
2123}
2124
2125/*
2126 * The documentation block below uses an include (instead of inline text)
2127 * because the included text has non-ASCII characters (which are not allowed in a C file).
2128 */
2129
2130/*
2131 *
2132 * call-seq:
2133 * String.new(string = ''.encode(Encoding::ASCII_8BIT) , **options) -> new_string
2134 *
2135 * :include: doc/string/new.rdoc
2136 *
2137 */
2138
2139static VALUE
2140rb_str_init(int argc, VALUE *argv, VALUE str)
2141{
2142 static ID keyword_ids[2];
2143 VALUE orig, opt, venc, vcapa;
2144 VALUE kwargs[2];
2145 rb_encoding *enc = 0;
2146 int n;
2147
2148 if (!keyword_ids[0]) {
2149 keyword_ids[0] = rb_id_encoding();
2150 CONST_ID(keyword_ids[1], "capacity");
2151 }
2152
2153 n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2154 if (!NIL_P(opt)) {
2155 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2156 venc = kwargs[0];
2157 vcapa = kwargs[1];
2158 if (!NIL_OR_UNDEF_P(venc)) {
2159 enc = rb_to_encoding(venc);
2160 }
2161 if (!NIL_OR_UNDEF_P(vcapa)) {
2162 rb_len_t capa = NUM2LEN(vcapa);
2163 rb_len_t len = 0;
2164 int termlen = enc ? rb_enc_mbminlen(enc) : 1;
2165
2166 if (capa < STR_BUF_MIN_SIZE) {
2167 capa = STR_BUF_MIN_SIZE;
2168 }
2169 if (n == 1) {
2170 StringValue(orig);
2171 len = RSTRING_LEN(orig);
2172 if (capa < len) {
2173 capa = len;
2174 }
2175 if (orig == str) n = 0;
2176 }
2177 str_modifiable(str);
2178 if (STR_EMBED_P(str) || FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2179 /* make noembed always */
2180 const size_t size = (size_t)capa + termlen;
2181 const char *const old_ptr = RSTRING_PTR(str);
2182 const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
2183 char *new_ptr = ALLOC_N(char, size);
2184 if (STR_EMBED_P(str)) RUBY_ASSERT((rb_len_t)osize <= str_embed_capa(str));
2185 memcpy(new_ptr, old_ptr, osize < size ? osize : size);
2186 FL_UNSET_RAW(str, STR_SHARED|STR_NOFREE);
2187 RSTRING(str)->as.heap.ptr = new_ptr;
2188 }
2189 else if (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
2190 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
2191 (size_t)capa + termlen, STR_HEAP_SIZE(str));
2192 }
2193 STR_SET_LEN(str, len);
2194 TERM_FILL(&RSTRING(str)->as.heap.ptr[len], termlen);
2195 if (n == 1) {
2196 memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), len);
2197 if (!enc || rb_enc_get(orig) == enc) {
2198 rb_enc_cr_str_exact_copy(str, orig);
2199 enc = 0;
2200 }
2201 }
2202 FL_SET(str, STR_NOEMBED);
2203 RSTRING(str)->as.heap.aux.capa = capa;
2204 }
2205 else if (n == 1) {
2206 rb_str_replace(str, orig);
2207 }
2208 if (enc) {
2209 str_modifiable(str);
2210 rb_enc_raw_set(str, enc);
2212 }
2213 }
2214 else if (n == 1) {
2215 rb_str_replace(str, orig);
2216 }
2217 return str;
2218}
2219
2220/* :nodoc: */
2221static VALUE
2222rb_str_s_new(int argc, VALUE *argv, VALUE klass)
2223{
2224 if (klass != rb_cString) {
2225 return rb_class_new_instance_pass_kw(argc, argv, klass);
2226 }
2227
2228 static ID keyword_ids[2];
2229 VALUE orig, opt, encoding = Qnil, capacity = Qnil;
2230 VALUE kwargs[2];
2231 rb_encoding *enc = NULL;
2232
2233 int n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2234 if (NIL_P(opt)) {
2235 return rb_class_new_instance_pass_kw(argc, argv, klass);
2236 }
2237
2238 keyword_ids[0] = rb_id_encoding();
2239 CONST_ID(keyword_ids[1], "capacity");
2240 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2241 encoding = kwargs[0];
2242 capacity = kwargs[1];
2243
2244 if (n == 1) {
2245 orig = StringValue(orig);
2246 }
2247 else {
2248 orig = Qnil;
2249 }
2250
2251 if (UNDEF_P(encoding)) {
2252 if (!NIL_P(orig)) {
2253 encoding = rb_obj_encoding(orig);
2254 }
2255 }
2256
2257 if (!UNDEF_P(encoding)) {
2258 enc = rb_to_encoding(encoding);
2259 }
2260
2261 // If capacity is nil, we're basically just duping `orig`.
2262 if (UNDEF_P(capacity)) {
2263 if (NIL_P(orig)) {
2264 VALUE empty_str = str_new(klass, "", 0);
2265 if (enc) {
2266 rb_enc_associate(empty_str, enc);
2267 }
2268 return empty_str;
2269 }
2270 VALUE copy = str_duplicate(klass, orig);
2271 rb_enc_associate(copy, enc);
2272 ENC_CODERANGE_CLEAR(copy);
2273 return copy;
2274 }
2275
2276 rb_len_t capa = 0;
2277 capa = NUM2LEN(capacity);
2278 if (capa < 0) {
2279 capa = 0;
2280 }
2281
2282 if (!NIL_P(orig)) {
2283 rb_len_t orig_capa = rb_str_capacity(orig);
2284 if (orig_capa > capa) {
2285 capa = orig_capa;
2286 }
2287 }
2288
2289 VALUE str = str_enc_new(klass, NULL, capa, enc);
2290 STR_SET_LEN(str, 0);
2291 TERM_FILL(RSTRING_PTR(str), enc ? rb_enc_mbmaxlen(enc) : 1);
2292
2293 if (!NIL_P(orig)) {
2294 rb_str_buf_append(str, orig);
2295 }
2296
2297 return str;
2298}
2299
2300#ifdef NONASCII_MASK
2301#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2302
2303/*
2304 * UTF-8 leading bytes have either 0xxxxxxx or 11xxxxxx
2305 * bit representation. (see https://en.wikipedia.org/wiki/UTF-8)
2306 * Therefore, the following pseudocode can detect UTF-8 leading bytes.
2307 *
2308 * if (!(byte & 0x80))
2309 * byte |= 0x40; // turn on bit6
2310 * return ((byte>>6) & 1); // bit6 represent whether this byte is leading or not.
2311 *
2312 * This function calculates whether a byte is leading or not for all bytes
2313 * in the argument word by concurrently using the above logic, and then
2314 * adds up the number of leading bytes in the word.
2315 */
2316static inline uintptr_t
2317count_utf8_lead_bytes_with_word(const uintptr_t *s)
2318{
2319 uintptr_t d = *s;
2320
2321 /* Transform so that bit0 indicates whether we have a UTF-8 leading byte or not. */
2322 d = (d>>6) | (~d>>7);
2323 d &= NONASCII_MASK >> 7;
2324
2325 /* Gather all bytes. */
2326#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2327 /* use only if it can use POPCNT */
2328 return rb_popcount_intptr(d);
2329#else
2330 d += (d>>8);
2331 d += (d>>16);
2332# if SIZEOF_VOIDP == 8
2333 d += (d>>32);
2334# endif
2335 return (d&0xF);
2336#endif
2337}
2338#endif
2339
2340static inline rb_len_t
2341enc_strlen(const char *p, const char *e, rb_encoding *enc, int cr)
2342{
2343 rb_len_t c;
2344 const char *q;
2345
2346 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2347 rb_len_t diff = (rb_len_t)(e - p);
2348 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2349 }
2350#ifdef NONASCII_MASK
2351 else if (cr == ENC_CODERANGE_VALID && enc == rb_utf8_encoding()) {
2352 uintptr_t len = 0;
2353 if ((int)sizeof(uintptr_t) * 2 < e - p) {
2354 const uintptr_t *s, *t;
2355 const uintptr_t lowbits = sizeof(uintptr_t) - 1;
2356 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2357 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
2358 while (p < (const char *)s) {
2359 if (is_utf8_lead_byte(*p)) len++;
2360 p++;
2361 }
2362 while (s < t) {
2363 len += count_utf8_lead_bytes_with_word(s);
2364 s++;
2365 }
2366 p = (const char *)s;
2367 }
2368 while (p < e) {
2369 if (is_utf8_lead_byte(*p)) len++;
2370 p++;
2371 }
2372 return (rb_len_t)len;
2373 }
2374#endif
2375 else if (rb_enc_asciicompat(enc)) {
2376 c = 0;
2377 if (ENC_CODERANGE_CLEAN_P(cr)) {
2378 while (p < e) {
2379 q = search_nonascii(p, e);
2380 if (!q)
2381 return c + (e - p);
2382 c += q - p;
2383 p = q;
2384 p += rb_enc_fast_mbclen(p, e, enc);
2385 c++;
2386 }
2387 }
2388 else {
2389 while (p < e) {
2390 q = search_nonascii(p, e);
2391 if (!q)
2392 return c + (e - p);
2393 c += q - p;
2394 p = q;
2395 p += rb_enc_mbclen(p, e, enc);
2396 c++;
2397 }
2398 }
2399 return c;
2400 }
2401
2402 for (c=0; p<e; c++) {
2403 p += rb_enc_mbclen(p, e, enc);
2404 }
2405 return c;
2406}
2407
2409rb_enc_strlen(const char *p, const char *e, rb_encoding *enc)
2410{
2411 return enc_strlen(p, e, enc, ENC_CODERANGE_UNKNOWN);
2412}
2413
2414/* To get strlen with cr
2415 * Note that given cr is not used.
2416 */
2418rb_enc_strlen_cr(const char *p, const char *e, rb_encoding *enc, int *cr)
2419{
2420 rb_len_t c;
2421 const char *q;
2422 int ret;
2423
2424 *cr = 0;
2425 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2426 rb_len_t diff = (rb_len_t)(e - p);
2427 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2428 }
2429 else if (rb_enc_asciicompat(enc)) {
2430 c = 0;
2431 while (p < e) {
2432 q = search_nonascii(p, e);
2433 if (!q) {
2434 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2435 return c + (e - p);
2436 }
2437 c += q - p;
2438 p = q;
2439 ret = rb_enc_precise_mbclen(p, e, enc);
2440 if (MBCLEN_CHARFOUND_P(ret)) {
2441 *cr |= ENC_CODERANGE_VALID;
2442 p += MBCLEN_CHARFOUND_LEN(ret);
2443 }
2444 else {
2446 p++;
2447 }
2448 c++;
2449 }
2450 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2451 return c;
2452 }
2453
2454 for (c=0; p<e; c++) {
2455 ret = rb_enc_precise_mbclen(p, e, enc);
2456 if (MBCLEN_CHARFOUND_P(ret)) {
2457 *cr |= ENC_CODERANGE_VALID;
2458 p += MBCLEN_CHARFOUND_LEN(ret);
2459 }
2460 else {
2462 if (p + rb_enc_mbminlen(enc) <= e)
2463 p += rb_enc_mbminlen(enc);
2464 else
2465 p = e;
2466 }
2467 }
2468 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2469 return c;
2470}
2471
2472/* enc must be str's enc or rb_enc_check(str, str2) */
2473static rb_len_t
2474str_strlen(VALUE str, rb_encoding *enc)
2475{
2476 const char *p, *e;
2477 int cr;
2478
2479 if (single_byte_optimizable(str)) return RSTRING_LEN(str);
2480 if (!enc) enc = STR_ENC_GET(str);
2481 p = RSTRING_PTR(str);
2482 e = RSTRING_END(str);
2483 cr = ENC_CODERANGE(str);
2484
2485 if (cr == ENC_CODERANGE_UNKNOWN) {
2486 rb_len_t n = rb_enc_strlen_cr(p, e, enc, &cr);
2487 if (cr) ENC_CODERANGE_SET(str, cr);
2488 return n;
2489 }
2490 else {
2491 return enc_strlen(p, e, enc, cr);
2492 }
2493}
2494
2497{
2498 return str_strlen(str, NULL);
2499}
2500
2501/*
2502 * call-seq:
2503 * length -> integer
2504 *
2505 * :include: doc/string/length.rdoc
2506 *
2507 */
2508
2509VALUE
2511{
2512 return LEN2NUM(str_strlen(str, NULL));
2513}
2514
2515/*
2516 * call-seq:
2517 * bytesize -> integer
2518 *
2519 * :include: doc/string/bytesize.rdoc
2520 *
2521 */
2522
2523VALUE
2524rb_str_bytesize(VALUE str)
2525{
2526 return LEN2NUM(RSTRING_LEN(str));
2527}
2528
2529/*
2530 * call-seq:
2531 * empty? -> true or false
2532 *
2533 * Returns whether the length of +self+ is zero:
2534 *
2535 * 'hello'.empty? # => false
2536 * ' '.empty? # => false
2537 * ''.empty? # => true
2538 *
2539 * Related: see {Querying}[rdoc-ref:String@Querying].
2540 */
2541
2542static VALUE
2543rb_str_empty(VALUE str)
2544{
2545 return RBOOL(RSTRING_LEN(str) == 0);
2546}
2547
2548/*
2549 * call-seq:
2550 * self + other_string -> new_string
2551 *
2552 * Returns a new string containing +other_string+ concatenated to +self+:
2553 *
2554 * 'Hello from ' + self.to_s # => "Hello from main"
2555 *
2556 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2557 */
2558
2559VALUE
2561{
2562 VALUE str3;
2563 rb_encoding *enc;
2564 const char *ptr1, *ptr2;
2565 char *ptr3;
2566 rb_len_t len1, len2;
2567 int termlen;
2568
2569 StringValue(str2);
2570 enc = rb_enc_check_str(str1, str2);
2571 RSTRING_GETMEM(str1, ptr1, len1);
2572 RSTRING_GETMEM(str2, ptr2, len2);
2573 termlen = rb_enc_mbminlen(enc);
2574 if (len1 > RB_LEN_MAX - len2) {
2575 rb_raise(rb_eArgError, "string size too big");
2576 }
2577 str3 = str_enc_new(rb_cString, 0, len1+len2, enc);
2578 ptr3 = RSTRING_PTR(str3);
2579 memcpy(ptr3, ptr1, len1);
2580 memcpy(ptr3+len1, ptr2, len2);
2581 TERM_FILL(&ptr3[len1+len2], termlen);
2582
2583 ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
2585 RB_GC_GUARD(str1);
2586 RB_GC_GUARD(str2);
2587 return str3;
2588}
2589
2590/* A variant of rb_str_plus that does not raise but return Qundef instead. */
2591VALUE
2592rb_str_opt_plus(VALUE str1, VALUE str2)
2593{
2596 rb_len_t len1, len2;
2597 MAYBE_UNUSED(char) *ptr1, *ptr2;
2598 RSTRING_GETMEM(str1, ptr1, len1);
2599 RSTRING_GETMEM(str2, ptr2, len2);
2600 int enc1 = rb_enc_get_index(str1);
2601 int enc2 = rb_enc_get_index(str2);
2602
2603 if (enc1 < 0) {
2604 return Qundef;
2605 }
2606 else if (enc2 < 0) {
2607 return Qundef;
2608 }
2609 else if (enc1 != enc2) {
2610 return Qundef;
2611 }
2612 else if (len1 > RB_LEN_MAX - len2) {
2613 return Qundef;
2614 }
2615 else {
2616 return rb_str_plus(str1, str2);
2617 }
2618
2619}
2620
2621/*
2622 * call-seq:
2623 * self * n -> new_string
2624 *
2625 * Returns a new string containing +n+ copies of +self+:
2626 *
2627 * 'Ho!' * 3 # => "Ho!Ho!Ho!"
2628 * 'No!' * 0 # => ""
2629 *
2630 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2631 */
2632
2633VALUE
2635{
2636 VALUE str2;
2637 rb_len_t n, len;
2638 char *ptr2;
2639 int termlen;
2640
2641 if (times == INT2FIX(1)) {
2642 return str_duplicate(rb_cString, str);
2643 }
2644 if (times == INT2FIX(0)) {
2645 str2 = str_alloc_embed(rb_cString, 0);
2646 rb_enc_copy(str2, str);
2647 return str2;
2648 }
2649 len = NUM2LEN(times);
2650 if (len < 0) {
2651 rb_raise(rb_eArgError, "negative argument");
2652 }
2653 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2654 if (STR_EMBEDDABLE_P(len, 1)) {
2655 str2 = str_alloc_embed(rb_cString, len + 1);
2656 memset(RSTRING_PTR(str2), 0, len + 1);
2657 }
2658 else {
2659 str2 = str_alloc_heap(rb_cString);
2660 RSTRING(str2)->as.heap.aux.capa = len;
2661 RSTRING(str2)->as.heap.ptr = ZALLOC_N(char, (size_t)len + 1);
2662 }
2663 STR_SET_LEN(str2, len);
2664 rb_enc_copy(str2, str);
2665 return str2;
2666 }
2667 if (len && RB_LEN_MAX/len < RSTRING_LEN(str)) {
2668 rb_raise(rb_eArgError, "argument too big");
2669 }
2670
2671 len *= RSTRING_LEN(str);
2672 termlen = TERM_LEN(str);
2673 str2 = str_enc_new(rb_cString, 0, len, STR_ENC_GET(str));
2674 ptr2 = RSTRING_PTR(str2);
2675 if (len) {
2676 n = RSTRING_LEN(str);
2677 memcpy(ptr2, RSTRING_PTR(str), n);
2678 while (n <= len/2) {
2679 memcpy(ptr2 + n, ptr2, n);
2680 n *= 2;
2681 }
2682 memcpy(ptr2 + n, ptr2, len-n);
2683 }
2684 STR_SET_LEN(str2, len);
2685 TERM_FILL(&ptr2[len], termlen);
2686 rb_enc_cr_str_copy_for_substr(str2, str);
2687
2688 return str2;
2689}
2690
2691/*
2692 * call-seq:
2693 * self % object -> new_string
2694 *
2695 * Returns the result of formatting +object+ into the format specifications
2696 * contained in +self+
2697 * (see {Format Specifications}[rdoc-ref:language/format_specifications.rdoc]):
2698 *
2699 * '%05d' % 123 # => "00123"
2700 *
2701 * If +self+ contains multiple format specifications,
2702 * +object+ must be an array or hash containing the objects to be formatted:
2703 *
2704 * '%-5s: %016x' % [ 'ID', self.object_id ] # => "ID : 00002b054ec93168"
2705 * 'foo = %{foo}' % {foo: 'bar'} # => "foo = bar"
2706 * 'foo = %{foo}, baz = %{baz}' % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
2707 *
2708 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2709 */
2710
2711static VALUE
2712rb_str_format_m(VALUE str, VALUE arg)
2713{
2714 VALUE tmp = rb_check_array_type(arg);
2715
2716 if (!NIL_P(tmp)) {
2717 VALUE result = rb_str_format_ary(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str, tmp);
2718 RB_GC_GUARD(tmp);
2719 return result;
2720 }
2721 return rb_str_format(1, &arg, str);
2722}
2723
2724static inline void
2725rb_check_lockedtmp(VALUE str)
2726{
2727 if (FL_TEST(str, STR_TMPLOCK)) {
2728 rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked");
2729 }
2730}
2731
2732// If none of these flags are set, we know we have an modifiable string.
2733// If any is set, we need to do more detailed checks.
2734#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2735static inline void
2736str_modifiable(VALUE str)
2737{
2738 RUBY_ASSERT(ruby_thread_has_gvl_p());
2739
2740 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2741 if (CHILLED_STRING_P(str)) {
2742 CHILLED_STRING_MUTATED(str);
2743 }
2744 rb_check_lockedtmp(str);
2745 rb_check_frozen(str);
2746 }
2747}
2748
2749static inline int
2750str_dependent_p(VALUE str)
2751{
2752 if (STR_EMBED_P(str) || !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2753 return FALSE;
2754 }
2755 else {
2756 return TRUE;
2757 }
2758}
2759
2760// If none of these flags are set, we know we have an independent string.
2761// If any is set, we need to do more detailed checks.
2762#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2763static inline int
2764str_independent(VALUE str)
2765{
2766 RUBY_ASSERT(ruby_thread_has_gvl_p());
2767
2768 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2769 str_modifiable(str);
2770 return !str_dependent_p(str);
2771 }
2772 return TRUE;
2773}
2774
2775static void
2776str_make_independent_expand(VALUE str, rb_len_t len, rb_len_t expand, const int termlen)
2777{
2778 RUBY_ASSERT(ruby_thread_has_gvl_p());
2779
2780 char *ptr;
2781 char *oldptr;
2782 rb_len_t capa = len + expand;
2783
2784 if (len > capa) len = capa;
2785
2786 if (!STR_EMBED_P(str) && str_embed_capa(str) >= capa + termlen) {
2787 ptr = RSTRING(str)->as.heap.ptr;
2788 STR_SET_EMBED(str);
2789 memcpy(RSTRING(str)->as.embed.ary, ptr, len);
2790 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
2791 STR_SET_LEN(str, len);
2792 return;
2793 }
2794
2795 ptr = ALLOC_N(char, (size_t)capa + termlen);
2796 oldptr = RSTRING_PTR(str);
2797 if (oldptr) {
2798 memcpy(ptr, oldptr, len);
2799 }
2800 if (FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2801 SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
2802 }
2803 STR_SET_NOEMBED(str);
2804 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2805 TERM_FILL(ptr + len, termlen);
2806 RSTRING(str)->as.heap.ptr = ptr;
2807 STR_SET_LEN(str, len);
2808 RSTRING(str)->as.heap.aux.capa = capa;
2809}
2810
2811void
2812rb_str_modify(VALUE str)
2813{
2814 if (!str_independent(str))
2815 str_make_independent(str);
2817}
2818
2819void
2821{
2822 RUBY_ASSERT(ruby_thread_has_gvl_p());
2823
2824 int termlen = TERM_LEN(str);
2825 rb_len_t len = RSTRING_LEN(str);
2826
2827 if (expand < 0) {
2828 rb_raise(rb_eArgError, "negative expanding string size");
2829 }
2830 if (expand >= RB_LEN_MAX - len) {
2831 rb_raise(rb_eArgError, "string size too big");
2832 }
2833
2834 if (!str_independent(str)) {
2835 str_make_independent_expand(str, len, expand, termlen);
2836 }
2837 else if (expand > 0) {
2838 RESIZE_CAPA_TERM(str, len + expand, termlen);
2839 }
2841}
2842
2843/* As rb_str_modify(), but don't clear coderange */
2844static void
2845str_modify_keep_cr(VALUE str)
2846{
2847 if (!str_independent(str))
2848 str_make_independent(str);
2850 /* Force re-scan later */
2852}
2853
2854static inline void
2855str_discard(VALUE str)
2856{
2857 str_modifiable(str);
2858 if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2859 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2860 RSTRING(str)->as.heap.ptr = 0;
2861 STR_SET_LEN(str, 0);
2862 }
2863}
2864
2865void
2867{
2868 int encindex = rb_enc_get_index(str);
2869
2870 if (RB_UNLIKELY(encindex == -1)) {
2871 rb_raise(rb_eTypeError, "not encoding capable object");
2872 }
2873
2874 if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
2875 return;
2876 }
2877
2878 rb_encoding *enc = rb_enc_from_index(encindex);
2879 if (!rb_enc_asciicompat(enc)) {
2880 rb_raise(rb_eEncCompatError, "ASCII incompatible encoding: %s", rb_enc_name(enc));
2881 }
2882}
2883
2884VALUE
2886{
2887 RUBY_ASSERT(ruby_thread_has_gvl_p());
2888
2889 VALUE s = *ptr;
2890 if (!RB_TYPE_P(s, T_STRING)) {
2891 s = rb_str_to_str(s);
2892 *ptr = s;
2893 }
2894 return s;
2895}
2896
2897char *
2899{
2900 VALUE str = rb_string_value(ptr);
2901 return RSTRING_PTR(str);
2902}
2903
2904static const char *
2905str_null_char(const char *s, rb_len_t len, const int minlen, rb_encoding *enc)
2906{
2907 const char *e = s + len;
2908
2909 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2910 if (zero_filled(s, minlen)) return s;
2911 }
2912 return 0;
2913}
2914
2915static char *
2916str_fill_term(VALUE str, char *s, rb_len_t len, int termlen)
2917{
2918 /* This function assumes that (capa + termlen) bytes of memory
2919 * is allocated, like many other functions in this file.
2920 */
2921 if (str_dependent_p(str)) {
2922 if (!zero_filled(s + len, termlen))
2923 str_make_independent_expand(str, len, 0L, termlen);
2924 }
2925 else {
2926 TERM_FILL(s + len, termlen);
2927 return s;
2928 }
2929 return RSTRING_PTR(str);
2930}
2931
2932void
2933rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen)
2934{
2935 rb_len_t capa = str_capacity(str, oldtermlen) + oldtermlen;
2936 rb_len_t len = RSTRING_LEN(str);
2937
2938 RUBY_ASSERT(capa >= len);
2939 if (capa - len < termlen) {
2940 rb_check_lockedtmp(str);
2941 str_make_independent_expand(str, len, 0L, termlen);
2942 }
2943 else if (str_dependent_p(str)) {
2944 if (termlen > oldtermlen)
2945 str_make_independent_expand(str, len, 0L, termlen);
2946 }
2947 else {
2948 if (!STR_EMBED_P(str)) {
2949 /* modify capa instead of realloc */
2950 RUBY_ASSERT(!FL_TEST((str), STR_SHARED));
2951 RSTRING(str)->as.heap.aux.capa = capa - termlen;
2952 }
2953 if (termlen > oldtermlen) {
2954 TERM_FILL(RSTRING_PTR(str) + len, termlen);
2955 }
2956 }
2957
2958 return;
2959}
2960
2961static char *
2962str_null_check(VALUE str, int *w)
2963{
2964 char *s = RSTRING_PTR(str);
2965 rb_len_t len = RSTRING_LEN(str);
2966 int minlen = 1;
2967
2968 if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
2969 rb_encoding *enc = rb_str_enc_get(str);
2970 minlen = rb_enc_mbminlen(enc);
2971
2972 if (minlen > 1) {
2973 *w = 1;
2974 if (str_null_char(s, len, minlen, enc)) {
2975 return NULL;
2976 }
2977 return str_fill_term(str, s, len, minlen);
2978 }
2979 }
2980
2981 *w = 0;
2982 if (!s || memchr(s, 0, len)) {
2983 return NULL;
2984 }
2985 if (s[len]) {
2986 s = str_fill_term(str, s, len, minlen);
2987 }
2988 return s;
2989}
2990
2991static char *str_to_cstr(VALUE str);
2992
2993const char *
2994rb_str_null_check(VALUE str)
2995{
2997
2998 const char *s;
2999 rb_len_t len;
3000 RSTRING_GETMEM(str, s, len);
3001
3002 if (RB_LIKELY(rb_str_enc_fastpath(str))) {
3003 if (!s || memchr(s, 0, len)) {
3004 rb_raise(rb_eArgError, "string contains null byte");
3005 }
3006 }
3007 else {
3008 str_to_cstr(str);
3009 }
3010
3011 return s;
3012}
3013
3014char *
3015rb_str_to_cstr(VALUE str)
3016{
3017 int w;
3018 return str_null_check(str, &w);
3019}
3020
3021char *
3023{
3024 VALUE str = rb_string_value(ptr);
3025 return str_to_cstr(str);
3026}
3027
3028static char *
3029str_to_cstr(VALUE str)
3030{
3031 int w;
3032 char *s = str_null_check(str, &w);
3033 if (!s) {
3034 if (w) {
3035 rb_raise(rb_eArgError, "string contains null char");
3036 }
3037 rb_raise(rb_eArgError, "string contains null byte");
3038 }
3039 return s;
3040}
3041
3042char *
3043rb_str_fill_terminator(VALUE str, const int newminlen)
3044{
3045 char *s = RSTRING_PTR(str);
3046 rb_len_t len = RSTRING_LEN(str);
3047 return str_fill_term(str, s, len, newminlen);
3048}
3049
3050VALUE
3052{
3053 str = rb_check_convert_type_with_id(str, T_STRING, "String", idTo_str);
3054 return str;
3055}
3056
3057/*
3058 * call-seq:
3059 * String.try_convert(object) -> object, new_string, or nil
3060 *
3061 * Attempts to convert the given +object+ to a string.
3062 *
3063 * If +object+ is already a string, returns +object+, unmodified.
3064 *
3065 * Otherwise if +object+ responds to <tt>:to_str</tt>,
3066 * calls <tt>object.to_str</tt> and returns the result.
3067 *
3068 * Returns +nil+ if +object+ does not respond to <tt>:to_str</tt>.
3069 *
3070 * Raises an exception unless <tt>object.to_str</tt> returns a string.
3071 */
3072static VALUE
3073rb_str_s_try_convert(VALUE dummy, VALUE str)
3074{
3075 return rb_check_string_type(str);
3076}
3077
3078static char*
3079str_nth_len(const char *p, const char *e, rb_len_t *nthp, rb_encoding *enc)
3080{
3081 rb_len_t nth = *nthp;
3082 if (rb_enc_mbmaxlen(enc) == 1) {
3083 p += nth;
3084 }
3085 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
3086 p += nth * rb_enc_mbmaxlen(enc);
3087 }
3088 else if (rb_enc_asciicompat(enc)) {
3089 const char *p2, *e2;
3090 int n;
3091
3092 while (p < e && 0 < nth) {
3093 e2 = p + nth;
3094 if (e < e2) {
3095 *nthp = nth;
3096 return (char *)e;
3097 }
3098 p2 = search_nonascii(p, e2);
3099 if (!p2) {
3100 nth -= e2 - p;
3101 *nthp = nth;
3102 return (char *)e2;
3103 }
3104 nth -= p2 - p;
3105 p = p2;
3106 n = rb_enc_mbclen(p, e, enc);
3107 p += n;
3108 nth--;
3109 }
3110 *nthp = nth;
3111 if (nth != 0) {
3112 return (char *)e;
3113 }
3114 return (char *)p;
3115 }
3116 else {
3117 while (p < e && nth--) {
3118 p += rb_enc_mbclen(p, e, enc);
3119 }
3120 }
3121 if (p > e) p = e;
3122 *nthp = nth;
3123 return (char*)p;
3124}
3125
3126char*
3127rb_enc_nth(const char *p, const char *e, rb_len_t nth, rb_encoding *enc)
3128{
3129 return str_nth_len(p, e, &nth, enc);
3130}
3131
3132static char*
3133str_nth(const char *p, const char *e, rb_len_t nth, rb_encoding *enc, int singlebyte)
3134{
3135 if (singlebyte)
3136 p += nth;
3137 else {
3138 p = str_nth_len(p, e, &nth, enc);
3139 }
3140 if (!p) return 0;
3141 if (p > e) p = e;
3142 return (char *)p;
3143}
3144
3145/* char offset to byte offset */
3146static rb_len_t
3147str_offset(const char *p, const char *e, rb_len_t nth, rb_encoding *enc, int singlebyte)
3148{
3149 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3150 if (!pp) return e - p;
3151 return pp - p;
3152}
3153
3156{
3157 return str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
3158 STR_ENC_GET(str), single_byte_optimizable(str));
3159}
3160
3161#ifdef NONASCII_MASK
3162static char *
3163str_utf8_nth(const char *p, const char *e, rb_len_t *nthp)
3164{
3165 rb_len_t nth = *nthp;
3166 if ((int)SIZEOF_VOIDP * 2 < e - p && (int)SIZEOF_VOIDP * 2 < nth) {
3167 const uintptr_t *s, *t;
3168 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3169 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3170 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
3171 while (p < (const char *)s) {
3172 if (is_utf8_lead_byte(*p)) nth--;
3173 p++;
3174 }
3175 do {
3176 nth -= count_utf8_lead_bytes_with_word(s);
3177 s++;
3178 } while (s < t && (int)SIZEOF_VOIDP <= nth);
3179 p = (char *)s;
3180 }
3181 while (p < e) {
3182 if (is_utf8_lead_byte(*p)) {
3183 if (nth == 0) break;
3184 nth--;
3185 }
3186 p++;
3187 }
3188 *nthp = nth;
3189 return (char *)p;
3190}
3191
3192static rb_len_t
3193str_utf8_offset(const char *p, const char *e, rb_len_t nth)
3194{
3195 const char *pp = str_utf8_nth(p, e, &nth);
3196 return pp - p;
3197}
3198#endif
3199
3200/* byte offset to char offset */
3203{
3204 if (single_byte_optimizable(str) || pos < 0)
3205 return pos;
3206 else {
3207 const char *p = RSTRING_PTR(str);
3208 return enc_strlen(p, p + pos, STR_ENC_GET(str), ENC_CODERANGE(str));
3209 }
3210}
3211
3212static VALUE
3213str_subseq(VALUE str, rb_len_t beg, rb_len_t len)
3214{
3215 VALUE str2;
3216
3217 RUBY_ASSERT(beg >= 0);
3218 RUBY_ASSERT(len >= 0);
3219 RUBY_ASSERT(beg+len <= RSTRING_LEN(str));
3220
3221 const int termlen = TERM_LEN(str);
3222 if (!SHARABLE_SUBSTRING_P(str, beg, len)) {
3223 str2 = rb_enc_str_new(RSTRING_PTR(str) + beg, len, rb_str_enc_get(str));
3224 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
3226 }
3227 RB_GC_GUARD(str);
3228 return str2;
3229 }
3230
3231 /* Sharing allocates a shared root as well unless str can be one itself, so
3232 * a copy is worth a larger slot only when it saves that second object. */
3233 const bool root_available = STR_SHARED_P(str) ||
3234 RB_FL_TEST_RAW(str, FL_FREEZE | STR_CHILLED) == FL_FREEZE;
3235 const size_t max_embed_size = root_available ?
3236 rb_gc_size_slot_size(sizeof(struct RString)) : STR_COPY_MAX_EMBED_SIZE;
3237 const size_t embed_size = rb_str_embed_size(len, termlen);
3238
3239 if (embed_size <= max_embed_size && rb_gc_size_allocatable_p(embed_size)) {
3240 str2 = str_alloc_embed(rb_cString, len + termlen);
3241 char *ptr2 = RSTRING(str2)->as.embed.ary;
3242 memcpy(ptr2, RSTRING_PTR(str) + beg, len);
3243 TERM_FILL(ptr2 + len, termlen);
3244
3245 STR_SET_LEN(str2, len);
3246 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
3248 }
3249
3250 RB_GC_GUARD(str);
3251 }
3252 else {
3253 str2 = str_alloc_heap(rb_cString);
3254 str_replace_shared(str2, str);
3255 RUBY_ASSERT(!STR_EMBED_P(str2));
3256 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
3257 ENC_CODERANGE_CLEAR(str2);
3258 }
3259
3260 RSTRING(str2)->as.heap.ptr += beg;
3261 if (RSTRING_LEN(str2) > len) {
3262 STR_SET_LEN(str2, len);
3263 }
3264 }
3265
3266 return str2;
3267}
3268
3269VALUE
3271{
3272 VALUE str2 = str_subseq(str, beg, len);
3273 rb_enc_cr_str_copy_for_substr(str2, str);
3274 return str2;
3275}
3276
3277char *
3279{
3280 rb_len_t len = *lenp;
3281 rb_len_t slen = -1L;
3282 const rb_len_t blen = RSTRING_LEN(str);
3283 rb_encoding *enc = STR_ENC_GET(str);
3284 const char *p, *s = RSTRING_PTR(str), *e = s + blen;
3285
3286 if (len < 0) return 0;
3287 if (beg < 0 && -beg < 0) return 0;
3288 if (!blen) {
3289 len = 0;
3290 }
3291 if (single_byte_optimizable(str)) {
3292 if (beg > blen) return 0;
3293 if (beg < 0) {
3294 beg += blen;
3295 if (beg < 0) return 0;
3296 }
3297 if (len > blen - beg)
3298 len = blen - beg;
3299 if (len < 0) return 0;
3300 p = s + beg;
3301 goto end;
3302 }
3303 if (beg < 0) {
3304 if (len > -beg) len = -beg;
3305 if ((ENC_CODERANGE(str) == ENC_CODERANGE_VALID) &&
3306 (-beg * rb_enc_mbmaxlen(enc) < blen / 8)) {
3307 beg = -beg;
3308 while (beg-- > len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3309 p = e;
3310 if (!p) return 0;
3311 while (len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3312 if (!p) return 0;
3313 len = e - p;
3314 goto end;
3315 }
3316 else {
3317 slen = str_strlen(str, enc);
3318 beg += slen;
3319 if (beg < 0) return 0;
3320 p = s + beg;
3321 if (len == 0) goto end;
3322 }
3323 }
3324 else if (beg > 0 && beg > blen) {
3325 return 0;
3326 }
3327 if (len == 0) {
3328 if (beg > str_strlen(str, enc)) return 0; /* str's enc */
3329 p = s + beg;
3330 }
3331#ifdef NONASCII_MASK
3332 else if (ENC_CODERANGE(str) == ENC_CODERANGE_VALID &&
3333 enc == rb_utf8_encoding()) {
3334 p = str_utf8_nth(s, e, &beg);
3335 if (beg > 0) return 0;
3336 len = str_utf8_offset(p, e, len);
3337 }
3338#endif
3339 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
3340 int char_sz = rb_enc_mbmaxlen(enc);
3341
3342 p = s + beg * char_sz;
3343 if (p > e) {
3344 return 0;
3345 }
3346 else if (len * char_sz > e - p)
3347 len = e - p;
3348 else
3349 len *= char_sz;
3350 }
3351 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3352 if (beg > 0) return 0;
3353 len = 0;
3354 }
3355 else {
3356 len = str_offset(p, e, len, enc, 0);
3357 }
3358 end:
3359 *lenp = len;
3360 RB_GC_GUARD(str);
3361 return (char *)p;
3362}
3363
3364static VALUE str_substr(VALUE str, rb_len_t beg, rb_len_t len, int empty);
3365
3366VALUE
3368{
3369 return str_substr(str, beg, len, TRUE);
3370}
3371
3372VALUE
3373rb_str_substr_two_fixnums(VALUE str, VALUE beg, VALUE len, int empty)
3374{
3375 return str_substr(str, NUM2LEN(beg), NUM2LEN(len), empty);
3376}
3377
3378static VALUE
3379str_substr(VALUE str, rb_len_t beg, rb_len_t len, int empty)
3380{
3381 const char *p = rb_str_subpos(str, beg, &len);
3382
3383 if (!p) return Qnil;
3384 if (!len && !empty) return Qnil;
3385
3386 beg = p - RSTRING_PTR(str);
3387
3388 VALUE str2 = str_subseq(str, beg, len);
3389 rb_enc_cr_str_copy_for_substr(str2, str);
3390 return str2;
3391}
3392
3393/* :nodoc: */
3394VALUE
3396{
3397 if (CHILLED_STRING_P(str)) {
3398 FL_UNSET_RAW(str, STR_CHILLED);
3399 }
3400
3401 if (OBJ_FROZEN(str)) return str;
3402 rb_str_resize(str, RSTRING_LEN(str));
3403 return rb_obj_freeze(str);
3404}
3405
3406/*
3407 * call-seq:
3408 * +string -> new_string or self
3409 *
3410 * Returns +self+ if +self+ is not frozen and can be mutated
3411 * without warning issuance.
3412 *
3413 * Otherwise returns <tt>self.dup</tt>, which is not frozen.
3414 *
3415 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
3416 */
3417static VALUE
3418str_uplus(VALUE str)
3419{
3420 if (OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3421 return rb_str_dup(str);
3422 }
3423 else {
3424 return str;
3425 }
3426}
3427
3428/*
3429 * call-seq:
3430 * -self -> frozen_string
3431 *
3432 * Returns a frozen string equal to +self+.
3433 *
3434 * The returned string is +self+ if and only if all of the following are true:
3435 *
3436 * - +self+ is already frozen.
3437 * - +self+ is an instance of \String (rather than of a subclass of \String)
3438 * - +self+ has no instance variables set on it.
3439 *
3440 * Otherwise, the returned string is a frozen copy of +self+.
3441 *
3442 * Returning +self+, when possible, saves duplicating +self+;
3443 * see {Data deduplication}[https://en.wikipedia.org/wiki/Data_deduplication].
3444 *
3445 * It may also save duplicating other, already-existing, strings:
3446 *
3447 * s0 = 'foo'
3448 * s1 = 'foo'
3449 * s0.object_id == s1.object_id # => false
3450 * (-s0).object_id == (-s1).object_id # => true
3451 *
3452 * Note that method #-@ is convenient for defining a constant:
3453 *
3454 * FileName = -'config/database.yml'
3455 *
3456 * While its alias #dedup is better suited for chaining:
3457 *
3458 * 'foo'.dedup.gsub!('o')
3459 *
3460 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
3461 */
3462static VALUE
3463str_uminus(VALUE str)
3464{
3465 if (!BARE_STRING_P(str) && !rb_obj_frozen_p(str)) {
3466 str = rb_str_dup(str);
3467 }
3468 return rb_fstring(str);
3469}
3470
3471RUBY_ALIAS_FUNCTION(rb_str_dup_frozen(VALUE str), rb_str_new_frozen, (str))
3472#define rb_str_dup_frozen rb_str_new_frozen
3473
3474VALUE
3476{
3477 rb_check_frozen(str);
3478 if (FL_TEST(str, STR_TMPLOCK)) {
3479 rb_raise(rb_eRuntimeError, "temporal locking already locked string");
3480 }
3481 FL_SET(str, STR_TMPLOCK);
3482 return str;
3483}
3484
3485VALUE
3487{
3488 rb_check_frozen(str);
3489 if (!FL_TEST(str, STR_TMPLOCK)) {
3490 rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string");
3491 }
3492 FL_UNSET(str, STR_TMPLOCK);
3493 return str;
3494}
3495
3496VALUE
3497rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg)
3498{
3499 rb_str_locktmp(str);
3500 return rb_ensure(func, arg, rb_str_unlocktmp, str);
3501}
3502
3503void
3505{
3506 RUBY_ASSERT(ruby_thread_has_gvl_p());
3507
3508 rb_len_t capa;
3509 const int termlen = TERM_LEN(str);
3510
3511 str_modifiable(str);
3512 if (STR_SHARED_P(str)) {
3513 rb_raise(rb_eRuntimeError, "can't set length of shared string");
3514 }
3515 if (len > (capa = (rb_len_t)str_capacity(str, termlen)) || len < 0) {
3516 rb_bug("probable buffer overflow: %"PRIdLEN" for %"PRIdLEN, len, capa);
3517 }
3518
3519 int cr = ENC_CODERANGE(str);
3520 if (len == 0) {
3521 /* Empty string does not contain non-ASCII */
3523 }
3524 else if (cr == ENC_CODERANGE_UNKNOWN) {
3525 /* Leave unknown. */
3526 }
3527 else if (len > RSTRING_LEN(str)) {
3528 if (ENC_CODERANGE_CLEAN_P(cr)) {
3529 /* Update the coderange regarding the extended part. */
3530 const char *const prev_end = RSTRING_END(str);
3531 const char *const new_end = RSTRING_PTR(str) + len;
3532 rb_encoding *enc = rb_enc_get(str);
3533 rb_str_coderange_scan_restartable(prev_end, new_end, enc, &cr);
3534 ENC_CODERANGE_SET(str, cr);
3535 }
3536 else if (cr == ENC_CODERANGE_BROKEN) {
3537 /* May be valid now, by appended part. */
3539 }
3540 }
3541 else if (len < RSTRING_LEN(str)) {
3542 if (cr != ENC_CODERANGE_7BIT) {
3543 /* ASCII-only string is keeping after truncated. Valid
3544 * and broken may be invalid or valid, leave unknown. */
3546 }
3547 }
3548
3549 STR_SET_LEN(str, len);
3550 TERM_FILL(&RSTRING_PTR(str)[len], termlen);
3551}
3552
3553VALUE
3554rb_str_resize(VALUE str, rb_len_t len)
3555{
3556 if (len < 0) {
3557 rb_raise(rb_eArgError, "negative string size (or size too big)");
3558 }
3559
3560 int independent = str_independent(str);
3561 rb_len_t slen = RSTRING_LEN(str);
3562 const int termlen = TERM_LEN(str);
3563
3564 if (slen > len || (termlen != 1 && slen < len)) {
3566 }
3567
3568 {
3569 rb_len_t capa;
3570 if (STR_EMBED_P(str)) {
3571 if (len == slen) return str;
3572 if (str_embed_capa(str) >= len + termlen) {
3573 STR_SET_LEN(str, len);
3574 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3575 return str;
3576 }
3577 str_make_independent_expand(str, slen, len - slen, termlen);
3578 }
3579 else if (str_embed_capa(str) >= len + termlen) {
3580 capa = RSTRING(str)->as.heap.aux.capa;
3581 char *ptr = STR_HEAP_PTR(str);
3582 STR_SET_EMBED(str);
3583 if (slen > len) slen = len;
3584 if (slen > 0) MEMCPY(RSTRING(str)->as.embed.ary, ptr, char, slen);
3585 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3586 STR_SET_LEN(str, len);
3587 if (independent) {
3588 SIZED_FREE_N(ptr, capa + termlen);
3589 }
3590 return str;
3591 }
3592 else if (!independent) {
3593 if (len == slen) return str;
3594 str_make_independent_expand(str, slen, len - slen, termlen);
3595 }
3596 else if ((capa = RSTRING(str)->as.heap.aux.capa) < len ||
3597 (capa - len) > (len < 1024 ? len : 1024)) {
3598 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
3599 (size_t)len + termlen, STR_HEAP_SIZE(str));
3600 RSTRING(str)->as.heap.aux.capa = len;
3601 }
3602 else if (len == slen) return str;
3603 STR_SET_LEN(str, len);
3604 TERM_FILL(RSTRING(str)->as.heap.ptr + len, termlen); /* sentinel */
3605 }
3606 return str;
3607}
3608
3609static void
3610str_ensure_available_capa(VALUE str, rb_len_t len)
3611{
3612 str_modify_keep_cr(str);
3613
3614 const int termlen = TERM_LEN(str);
3615 rb_len_t olen = RSTRING_LEN(str);
3616
3617 if (RB_UNLIKELY(olen > RB_LEN_MAX - len)) {
3618 rb_raise(rb_eArgError, "string sizes too big");
3619 }
3620
3621 rb_len_t total = olen + len;
3622 rb_len_t capa = str_capacity(str, termlen);
3623
3624 if (capa < total) {
3625 if (total >= RB_LEN_MAX / 2) {
3626 capa = total;
3627 }
3628 while (total > capa) {
3629 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3630 }
3631 RESIZE_CAPA_TERM(str, capa, termlen);
3632 }
3633}
3634
3635static VALUE
3636str_buf_cat4(VALUE str, const char *ptr, rb_len_t len, bool keep_cr)
3637{
3638 if (keep_cr) {
3639 str_modify_keep_cr(str);
3640 }
3641 else {
3642 rb_str_modify(str);
3643 }
3644 if (len == 0) return 0;
3645
3646 rb_len_t total, olen, off = -1;
3647 char *sptr;
3648 const int termlen = TERM_LEN(str);
3649
3650 RSTRING_GETMEM(str, sptr, olen);
3651 if (ptr >= sptr && ptr <= sptr + olen) {
3652 off = ptr - sptr;
3653 }
3654
3655 rb_len_t capa = str_capacity(str, termlen);
3656
3657 if (olen > RB_LEN_MAX - len) {
3658 rb_raise(rb_eArgError, "string sizes too big");
3659 }
3660 total = olen + len;
3661 if (capa < total) {
3662 if (total >= RB_LEN_MAX / 2) {
3663 capa = total;
3664 }
3665 while (total > capa) {
3666 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3667 }
3668 RESIZE_CAPA_TERM(str, capa, termlen);
3669 sptr = RSTRING_PTR(str);
3670 }
3671 if (off != -1) {
3672 ptr = sptr + off;
3673 }
3674 memcpy(sptr + olen, ptr, len);
3675 STR_SET_LEN(str, total);
3676 TERM_FILL(sptr + total, termlen); /* sentinel */
3677
3678 return str;
3679}
3680
3681#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3682#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3683
3684VALUE
3685rb_str_cat(VALUE str, const char *ptr, rb_len_t len)
3686{
3687 if (len == 0) return str;
3688 if (len < 0) {
3689 rb_raise(rb_eArgError, "negative string size (or size too big)");
3690 }
3691 return str_buf_cat(str, ptr, len);
3692}
3693
3694VALUE
3695rb_str_cat_cstr(VALUE str, const char *ptr)
3696{
3697 must_not_null(ptr);
3698 return rb_str_buf_cat(str, ptr, strlen(ptr));
3699}
3700
3701static void
3702rb_str_buf_cat_byte(VALUE str, unsigned char byte)
3703{
3704 RUBY_ASSERT(RB_ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT || RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII);
3705
3706 // We can't write directly to shared strings without impacting others, so we must make the string independent.
3707 if (UNLIKELY(!str_independent(str))) {
3708 str_make_independent(str);
3709 }
3710
3711 rb_len_t string_length = -1;
3712 const int null_terminator_length = 1;
3713 char *sptr;
3714 RSTRING_GETMEM(str, sptr, string_length);
3715
3716 // Ensure the resulting string wouldn't be too long.
3717 if (UNLIKELY(string_length > RB_LEN_MAX - 1)) {
3718 rb_raise(rb_eArgError, "string sizes too big");
3719 }
3720
3721 rb_len_t string_capacity = str_capacity(str, null_terminator_length);
3722
3723 // Get the code range before any modifications since those might clear the code range.
3724 int cr = ENC_CODERANGE(str);
3725
3726 // Check if the string has spare string_capacity to write the new byte.
3727 if (LIKELY(string_capacity >= string_length + 1)) {
3728 // In fast path we can write the new byte and note the string's new length.
3729 sptr[string_length] = byte;
3730 STR_SET_LEN(str, string_length + 1);
3731 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3732 }
3733 else {
3734 // If there's not enough string_capacity, make a call into the general string concatenation function.
3735 str_buf_cat(str, (char *)&byte, 1);
3736 }
3737
3738 // If the code range is already known, we can derive the resulting code range cheaply by looking at the byte we
3739 // just appended. If the code range is unknown, but the string was empty, then we can also derive the code range
3740 // by looking at the byte we just appended. Otherwise, we'd have to scan the bytes to determine the code range so
3741 // we leave it as unknown. It cannot be broken for binary strings so we don't need to handle that option.
3742 if (cr == ENC_CODERANGE_7BIT || string_length == 0) {
3743 if (ISASCII(byte)) {
3745 }
3746 else {
3748
3749 // Promote a US-ASCII string to ASCII-8BIT when a non-ASCII byte is appended.
3750 if (UNLIKELY(RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)) {
3751 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3752 }
3753 }
3754 }
3755}
3756
3757RUBY_ALIAS_FUNCTION(rb_str_buf_cat(VALUE str, const char *ptr, rb_len_t len), rb_str_cat, (str, ptr, len))
3758RUBY_ALIAS_FUNCTION(rb_str_buf_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3759RUBY_ALIAS_FUNCTION(rb_str_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3760
3761static VALUE
3762rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, rb_len_t len,
3763 int ptr_encindex, int ptr_cr, int *ptr_cr_ret)
3764{
3765 int str_encindex = ENCODING_GET(str);
3766 int res_encindex;
3767 int str_cr, res_cr;
3768 rb_encoding *str_enc, *ptr_enc;
3769
3770 str_cr = RSTRING_LEN(str) ? ENC_CODERANGE(str) : ENC_CODERANGE_7BIT;
3771
3772 if (str_encindex == ptr_encindex) {
3773 if (str_cr != ENC_CODERANGE_UNKNOWN && ptr_cr == ENC_CODERANGE_UNKNOWN) {
3774 ptr_cr = coderange_scan(ptr, len, rb_enc_from_index(ptr_encindex));
3775 }
3776 }
3777 else {
3778 str_enc = rb_enc_from_index(str_encindex);
3779 ptr_enc = rb_enc_from_index(ptr_encindex);
3780 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3781 if (len == 0)
3782 return str;
3783 if (RSTRING_LEN(str) == 0) {
3784 rb_str_buf_cat(str, ptr, len);
3785 ENCODING_CODERANGE_SET(str, ptr_encindex, ptr_cr);
3786 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3787 return str;
3788 }
3789 goto incompatible;
3790 }
3791 if (ptr_cr == ENC_CODERANGE_UNKNOWN) {
3792 ptr_cr = coderange_scan(ptr, len, ptr_enc);
3793 }
3794 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3795 if (ENCODING_IS_ASCII8BIT(str) || ptr_cr != ENC_CODERANGE_7BIT) {
3796 str_cr = rb_enc_str_coderange(str);
3797 }
3798 }
3799 }
3800 if (ptr_cr_ret)
3801 *ptr_cr_ret = ptr_cr;
3802
3803 if (str_encindex != ptr_encindex &&
3804 str_cr != ENC_CODERANGE_7BIT &&
3805 ptr_cr != ENC_CODERANGE_7BIT) {
3806 str_enc = rb_enc_from_index(str_encindex);
3807 ptr_enc = rb_enc_from_index(ptr_encindex);
3808 goto incompatible;
3809 }
3810
3811 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3812 res_encindex = str_encindex;
3813 res_cr = ENC_CODERANGE_UNKNOWN;
3814 }
3815 else if (str_cr == ENC_CODERANGE_7BIT) {
3816 if (ptr_cr == ENC_CODERANGE_7BIT) {
3817 res_encindex = str_encindex;
3818 res_cr = ENC_CODERANGE_7BIT;
3819 }
3820 else {
3821 res_encindex = ptr_encindex;
3822 res_cr = ptr_cr;
3823 }
3824 }
3825 else if (str_cr == ENC_CODERANGE_VALID) {
3826 res_encindex = str_encindex;
3827 if (ENC_CODERANGE_CLEAN_P(ptr_cr))
3828 res_cr = str_cr;
3829 else
3830 res_cr = ptr_cr;
3831 }
3832 else { /* str_cr == ENC_CODERANGE_BROKEN */
3833 res_encindex = str_encindex;
3834 res_cr = str_cr;
3835 if (0 < len) res_cr = ENC_CODERANGE_UNKNOWN;
3836 }
3837
3838 if (len < 0) {
3839 rb_raise(rb_eArgError, "negative string size (or size too big)");
3840 }
3841 str_buf_cat(str, ptr, len);
3842 ENCODING_CODERANGE_SET(str, res_encindex, res_cr);
3843 return str;
3844
3845 incompatible:
3846 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
3847 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3849}
3850
3851VALUE
3853{
3854 return rb_enc_cr_str_buf_cat(str, ptr, len,
3855 rb_enc_to_index(ptr_enc), ENC_CODERANGE_UNKNOWN, NULL);
3856}
3857
3858VALUE
3860{
3861 /* ptr must reference NUL terminated ASCII string. */
3862 int encindex = ENCODING_GET(str);
3863 rb_encoding *enc = rb_enc_from_index(encindex);
3864 if (rb_enc_asciicompat(enc)) {
3865 return rb_enc_cr_str_buf_cat(str, ptr, strlen(ptr),
3866 encindex, ENC_CODERANGE_7BIT, 0);
3867 }
3868 else {
3869 char *buf = ALLOCA_N(char, rb_enc_mbmaxlen(enc));
3870 while (*ptr) {
3871 unsigned int c = (unsigned char)*ptr;
3872 int len = rb_enc_codelen(c, enc);
3873 rb_enc_mbcput(c, buf, enc);
3874 rb_enc_cr_str_buf_cat(str, buf, len,
3875 encindex, ENC_CODERANGE_VALID, 0);
3876 ptr++;
3877 }
3878 return str;
3879 }
3880}
3881
3882VALUE
3884{
3885 int str2_cr = rb_enc_str_coderange(str2);
3886
3887 if (rb_str_enc_fastpath(str)) {
3888 switch (str2_cr) {
3889 case ENC_CODERANGE_7BIT:
3890 // If RHS is 7bit we can do simple concatenation
3891 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3892 RB_GC_GUARD(str2);
3893 return str;
3895 // If RHS is valid, we can do simple concatenation if encodings are the same
3896 if (ENCODING_GET_INLINED(str) == ENCODING_GET_INLINED(str2)) {
3897 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3898 int str_cr = ENC_CODERANGE(str);
3899 if (UNLIKELY(str_cr != ENC_CODERANGE_VALID)) {
3900 ENC_CODERANGE_SET(str, RB_ENC_CODERANGE_AND(str_cr, str2_cr));
3901 }
3902 RB_GC_GUARD(str2);
3903 return str;
3904 }
3905 }
3906 }
3907
3908 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3909 ENCODING_GET(str2), str2_cr, &str2_cr);
3910
3911 ENC_CODERANGE_SET(str2, str2_cr);
3912
3913 return str;
3914}
3915
3916VALUE
3918{
3919 StringValue(str2);
3920 return rb_str_buf_append(str, str2);
3921}
3922
3923VALUE
3924rb_str_concat_literals(size_t num, const VALUE *strary)
3925{
3926 VALUE str;
3927 size_t i, s = 0;
3928 rb_ulen_t len = 1;
3929
3930 if (UNLIKELY(!num)) return rb_str_new(0, 0);
3931 if (UNLIKELY(num == 1)) return rb_str_resurrect(strary[0]);
3932
3933 for (i = 0; i < num; ++i) { len += RSTRING_LEN(strary[i]); }
3934 str = rb_str_buf_new(len);
3935 str_enc_copy_direct(str, strary[0]);
3936
3937 for (i = s; i < num; ++i) {
3938 const VALUE v = strary[i];
3939 int encidx = ENCODING_GET(v);
3940
3941 rb_str_buf_append(str, v);
3942 if (encidx != ENCINDEX_US_ASCII) {
3943 if (ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)
3944 rb_enc_set_index(str, encidx);
3945 }
3946 }
3947 return str;
3948}
3949
3950/*
3951 * call-seq:
3952 * concat(*objects) -> string
3953 *
3954 * :include: doc/string/concat.rdoc
3955 */
3956static VALUE
3957rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
3958{
3959 str_modifiable(str);
3960
3961 if (argc == 1) {
3962 return rb_str_concat(str, argv[0]);
3963 }
3964 else if (argc > 1) {
3965 int i;
3966 VALUE arg_str = rb_str_tmp_new(0);
3967 rb_enc_copy(arg_str, str);
3968 for (i = 0; i < argc; i++) {
3969 rb_str_concat(arg_str, argv[i]);
3970 }
3971 rb_str_buf_append(str, arg_str);
3972 }
3973
3974 return str;
3975}
3976
3977/*
3978 * call-seq:
3979 * append_as_bytes(*objects) -> self
3980 *
3981 * Concatenates each object in +objects+ into +self+; returns +self+;
3982 * performs no encoding validation or conversion:
3983 *
3984 * s = 'foo'
3985 * s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82"
3986 * s.valid_encoding? # => false
3987 * s.append_as_bytes("\xAC 12")
3988 * s.valid_encoding? # => true
3989 *
3990 * When a given object is an integer,
3991 * the value is considered an 8-bit byte;
3992 * if the integer occupies more than one byte (i.e,. is greater than 255),
3993 * appends only the low-order byte (similar to String#setbyte):
3994 *
3995 * s = ""
3996 * s.append_as_bytes(0, 257) # => "\u0000\u0001"
3997 * s.bytesize # => 2
3998 *
3999 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4000 */
4001
4002VALUE
4003rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
4004{
4005 rb_len_t needed_capacity = 0;
4006 volatile VALUE t0;
4007 enum ruby_value_type *types = ALLOCV_N(enum ruby_value_type, t0, argc);
4008
4009 for (int index = 0; index < argc; index++) {
4010 VALUE obj = argv[index];
4011 enum ruby_value_type type = types[index] = rb_type(obj);
4012 switch (type) {
4013 case T_FIXNUM:
4014 case T_BIGNUM:
4015 needed_capacity++;
4016 break;
4017 case T_STRING:
4018 needed_capacity += RSTRING_LEN(obj);
4019 break;
4020 default:
4021 rb_raise(
4023 "wrong argument type %"PRIsVALUE" (expected String or Integer)",
4024 rb_obj_class(obj)
4025 );
4026 break;
4027 }
4028 }
4029
4030 str_ensure_available_capa(str, needed_capacity);
4031 char *sptr = RSTRING_END(str);
4032
4033 for (int index = 0; index < argc; index++) {
4034 VALUE obj = argv[index];
4035 enum ruby_value_type type = types[index];
4036 switch (type) {
4037 case T_FIXNUM:
4038 case T_BIGNUM: {
4039 argv[index] = obj = rb_int_and(obj, INT2FIX(0xff));
4040 char byte = (char)(NUM2INT(obj) & 0xFF);
4041 *sptr = byte;
4042 sptr++;
4043 break;
4044 }
4045 case T_STRING: {
4046 const char *ptr;
4047 rb_len_t len;
4048 RSTRING_GETMEM(obj, ptr, len);
4049 memcpy(sptr, ptr, len);
4050 sptr += len;
4051 break;
4052 }
4053 default:
4054 rb_bug("append_as_bytes arguments should have been validated");
4055 }
4056 }
4057
4058 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
4059 TERM_FILL(sptr, TERM_LEN(str)); /* sentinel */
4060
4061 int cr = ENC_CODERANGE(str);
4062 switch (cr) {
4063 case ENC_CODERANGE_7BIT: {
4064 for (int index = 0; index < argc; index++) {
4065 VALUE obj = argv[index];
4066 enum ruby_value_type type = types[index];
4067 switch (type) {
4068 case T_FIXNUM:
4069 case T_BIGNUM: {
4070 if (!ISASCII(NUM2INT(obj))) {
4071 goto clear_cr;
4072 }
4073 break;
4074 }
4075 case T_STRING: {
4076 if (ENC_CODERANGE(obj) != ENC_CODERANGE_7BIT) {
4077 goto clear_cr;
4078 }
4079 break;
4080 }
4081 default:
4082 rb_bug("append_as_bytes arguments should have been validated");
4083 }
4084 }
4085 break;
4086 }
4088 if (ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT) {
4089 goto keep_cr;
4090 }
4091 else {
4092 goto clear_cr;
4093 }
4094 break;
4095 default:
4096 goto clear_cr;
4097 break;
4098 }
4099
4100 clear_cr:
4101 // If no fast path was hit, we clear the coderange.
4102 // append_as_bytes is predominantly meant to be used in
4103 // buffering situation, hence it's likely the coderange
4104 // will never be scanned, so it's not worth spending time
4105 // precomputing the coderange except for simple and common
4106 // situations.
4108 keep_cr:
4109 ALLOCV_END(t0);
4110 return str;
4111}
4112
4113/*
4114 * call-seq:
4115 * self << object -> self
4116 *
4117 * Appends a string representation of +object+ to +self+;
4118 * returns +self+.
4119 *
4120 * If +object+ is a string, appends it to +self+:
4121 *
4122 * s = 'foo'
4123 * s << 'bar' # => "foobar"
4124 * s # => "foobar"
4125 *
4126 * If +object+ is an integer,
4127 * its value is considered a codepoint;
4128 * converts the value to a character before concatenating:
4129 *
4130 * s = 'foo'
4131 * s << 33 # => "foo!"
4132 *
4133 * Additionally, if the codepoint is in range <tt>0..0xff</tt>
4134 * and the encoding of +self+ is Encoding::US_ASCII,
4135 * changes the encoding to Encoding::ASCII_8BIT:
4136 *
4137 * s = 'foo'.encode(Encoding::US_ASCII)
4138 * s.encoding # => #<Encoding:US-ASCII>
4139 * s << 0xff # => "foo\xFF"
4140 * s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
4141 *
4142 * Raises RangeError if that codepoint is not representable in the encoding of +self+:
4143 *
4144 * s = 'foo'
4145 * s.encoding # => <Encoding:UTF-8>
4146 * s << 0x00110000 # 1114112 out of char range (RangeError)
4147 * s = 'foo'.encode(Encoding::EUC_JP)
4148 * s << 0x00800080 # invalid codepoint 0x800080 in EUC-JP (RangeError)
4149 *
4150 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4151 */
4152VALUE
4154{
4155 unsigned int code;
4156 rb_encoding *enc = STR_ENC_GET(str1);
4157 int encidx;
4158
4159 if (RB_INTEGER_TYPE_P(str2)) {
4160 if (rb_num_to_uint(str2, &code) == 0) {
4161 }
4162 else if (FIXNUM_P(str2)) {
4163 rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(str2));
4164 }
4165 else {
4166 rb_raise(rb_eRangeError, "bignum out of char range");
4167 }
4168 }
4169 else {
4170 return rb_str_append(str1, str2);
4171 }
4172
4173 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4174
4175 if (encidx >= 0) {
4176 rb_str_buf_cat_byte(str1, (unsigned char)code);
4177 }
4178 else {
4179 rb_len_t pos = RSTRING_LEN(str1);
4180 int cr = ENC_CODERANGE(str1);
4181 int len;
4182 char *buf;
4183
4184 switch (len = rb_enc_codelen(code, enc)) {
4185 case ONIGERR_INVALID_CODE_POINT_VALUE:
4186 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4187 break;
4188 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4189 case 0:
4190 rb_raise(rb_eRangeError, "%u out of char range", code);
4191 break;
4192 }
4193 buf = ALLOCA_N(char, len + 1);
4194 rb_enc_mbcput(code, buf, enc);
4195 if (rb_enc_precise_mbclen(buf, buf + len + 1, enc) != len) {
4196 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4197 }
4198 rb_str_resize(str1, pos+len);
4199 memcpy(RSTRING_PTR(str1) + pos, buf, len);
4200 if (cr == ENC_CODERANGE_7BIT && code > 127) {
4202 }
4203 else if (cr == ENC_CODERANGE_BROKEN) {
4205 }
4206 ENC_CODERANGE_SET(str1, cr);
4207 }
4208 return str1;
4209}
4210
4211int
4212rb_ascii8bit_appendable_encoding_index(rb_encoding *enc, unsigned int code)
4213{
4214 int encidx = rb_enc_to_index(enc);
4215
4216 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4217 /* US-ASCII automatically extended to ASCII-8BIT */
4218 if (code > 0xFF) {
4219 rb_raise(rb_eRangeError, "%u out of char range", code);
4220 }
4221 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4222 return ENCINDEX_ASCII_8BIT;
4223 }
4224 return encidx;
4225 }
4226 else {
4227 return -1;
4228 }
4229}
4230
4231/*
4232 * call-seq:
4233 * prepend(*other_strings) -> new_string
4234 *
4235 * Prefixes to +self+ the concatenation of the given +other_strings+; returns +self+:
4236 *
4237 * 'baz'.prepend('foo', 'bar') # => "foobarbaz"
4238 *
4239 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4240 *
4241 */
4242
4243static VALUE
4244rb_str_prepend_multi(int argc, VALUE *argv, VALUE str)
4245{
4246 str_modifiable(str);
4247
4248 if (argc == 1) {
4249 rb_str_update(str, 0L, 0L, argv[0]);
4250 }
4251 else if (argc > 1) {
4252 int i;
4253 VALUE arg_str = rb_str_tmp_new(0);
4254 rb_enc_copy(arg_str, str);
4255 for (i = 0; i < argc; i++) {
4256 rb_str_append(arg_str, argv[i]);
4257 }
4258 rb_str_update(str, 0L, 0L, arg_str);
4259 }
4260
4261 return str;
4262}
4263
4264st_index_t
4266{
4267 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) {
4268 st_index_t precomputed_hash;
4269 memcpy(&precomputed_hash, RSTRING_END(str) + TERM_LEN(str), sizeof(precomputed_hash));
4270
4271 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4272 return precomputed_hash;
4273 }
4274
4275 return str_do_hash(str);
4276}
4277
4278int
4280{
4281 rb_len_t len1, len2;
4282 const char *ptr1, *ptr2;
4283 RSTRING_GETMEM(str1, ptr1, len1);
4284 RSTRING_GETMEM(str2, ptr2, len2);
4285 return (len1 != len2 ||
4286 !rb_str_comparable(str1, str2) ||
4287 memcmp(ptr1, ptr2, len1) != 0);
4288}
4289
4290/*
4291 * call-seq:
4292 * hash -> integer
4293 *
4294 * :include: doc/string/hash.rdoc
4295 *
4296 */
4297
4298static VALUE
4299rb_str_hash_m(VALUE str)
4300{
4301 st_index_t hval = rb_str_hash(str);
4302 return ST2FIX(hval);
4303}
4304
4305#define lesser(a,b) (((a)>(b))?(b):(a))
4306
4307int
4309{
4310 int idx1, idx2;
4311 int rc1, rc2;
4312
4313 if (RSTRING_LEN(str1) == 0) return TRUE;
4314 if (RSTRING_LEN(str2) == 0) return TRUE;
4315 idx1 = ENCODING_GET(str1);
4316 idx2 = ENCODING_GET(str2);
4317 if (idx1 == idx2) return TRUE;
4318 rc1 = rb_enc_str_coderange(str1);
4319 rc2 = rb_enc_str_coderange(str2);
4320 if (rc1 == ENC_CODERANGE_7BIT) {
4321 if (rc2 == ENC_CODERANGE_7BIT) return TRUE;
4322 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4323 return TRUE;
4324 }
4325 if (rc2 == ENC_CODERANGE_7BIT) {
4326 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4327 return TRUE;
4328 }
4329 return FALSE;
4330}
4331
4332int
4334{
4335 rb_len_t len1, len2;
4336 const char *ptr1, *ptr2;
4337 int retval;
4338
4339 if (str1 == str2) return 0;
4340 RSTRING_GETMEM(str1, ptr1, len1);
4341 RSTRING_GETMEM(str2, ptr2, len2);
4342 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4343 if (len1 == len2) {
4344 if (!rb_str_comparable(str1, str2)) {
4345 if (ENCODING_GET(str1) > ENCODING_GET(str2))
4346 return 1;
4347 return -1;
4348 }
4349 return 0;
4350 }
4351 if (len1 > len2) return 1;
4352 return -1;
4353 }
4354 if (retval > 0) return 1;
4355 return -1;
4356}
4357
4358/*
4359 * call-seq:
4360 * self == other -> true or false
4361 *
4362 * Returns whether +other+ is equal to +self+.
4363 *
4364 * When +other+ is a string, returns whether +other+ has the same length and content as +self+:
4365 *
4366 * s = 'foo'
4367 * s == 'foo' # => true
4368 * s == 'food' # => false
4369 * s == 'FOO' # => false
4370 *
4371 * Returns +false+ if the two strings' encodings are not compatible:
4372 *
4373 * "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false
4374 *
4375 * When +other+ is not a string:
4376 *
4377 * - If +other+ responds to method <tt>to_str</tt>,
4378 * <tt>other == self</tt> is called and its return value is returned.
4379 * - If +other+ does not respond to <tt>to_str</tt>,
4380 * +false+ is returned.
4381 *
4382 * Related: {Comparing}[rdoc-ref:String@Comparing].
4383 */
4384
4385VALUE
4387{
4388 if (str1 == str2) return Qtrue;
4389 if (!RB_TYPE_P(str2, T_STRING)) {
4390 if (!rb_respond_to(str2, idTo_str)) {
4391 return Qfalse;
4392 }
4393 return rb_equal(str2, str1);
4394 }
4395 return rb_str_eql_internal(str1, str2);
4396}
4397
4398/*
4399 * call-seq:
4400 * eql?(object) -> true or false
4401 *
4402 * :include: doc/string/eql_p.rdoc
4403 *
4404 */
4405
4406VALUE
4407rb_str_eql(VALUE str1, VALUE str2)
4408{
4409 if (str1 == str2) return Qtrue;
4410 if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
4411 return rb_str_eql_internal(str1, str2);
4412}
4413
4414/*
4415 * call-seq:
4416 * self <=> other -> -1, 0, 1, or nil
4417 *
4418 * Compares +self+ and +other+,
4419 * evaluating their _contents_, not their _lengths_.
4420 *
4421 * Returns:
4422 *
4423 * - +-1+, if +self+ is smaller.
4424 * - +0+, if the two are equal.
4425 * - +1+, if +self+ is larger.
4426 * - +nil+, if the two are incomparable.
4427 *
4428 * Examples:
4429 *
4430 * 'a' <=> 'b' # => -1
4431 * 'a' <=> 'ab' # => -1
4432 * 'a' <=> 'a' # => 0
4433 * 'b' <=> 'a' # => 1
4434 * 'ab' <=> 'a' # => 1
4435 * 'a' <=> :a # => nil
4436 *
4437 * \Class \String includes module Comparable,
4438 * each of whose methods uses String#<=> for comparison.
4439 *
4440 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4441 */
4442
4443static VALUE
4444rb_str_cmp_m(VALUE str1, VALUE str2)
4445{
4446 int result;
4447 VALUE s = rb_check_string_type(str2);
4448 if (NIL_P(s)) {
4449 return rb_invcmp(str1, str2);
4450 }
4451 result = rb_str_cmp(str1, s);
4452 return INT2FIX(result);
4453}
4454
4455static VALUE str_casecmp(VALUE str1, VALUE str2);
4456static VALUE str_casecmp_p(VALUE str1, VALUE str2);
4457
4458/*
4459 * call-seq:
4460 * casecmp(other_string) -> -1, 0, 1, or nil
4461 *
4462 * Ignoring case, compares +self+ and +other_string+; returns:
4463 *
4464 * - -1 if <tt>self.downcase</tt> is smaller than <tt>other_string.downcase</tt>.
4465 * - 0 if the two are equal.
4466 * - 1 if <tt>self.downcase</tt> is larger than <tt>other_string.downcase</tt>.
4467 * - +nil+ if the two are incomparable.
4468 *
4469 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4470 *
4471 * Examples:
4472 *
4473 * 'foo'.casecmp('goo') # => -1
4474 * 'goo'.casecmp('foo') # => 1
4475 * 'foo'.casecmp('food') # => -1
4476 * 'food'.casecmp('foo') # => 1
4477 * 'FOO'.casecmp('foo') # => 0
4478 * 'foo'.casecmp('FOO') # => 0
4479 * 'foo'.casecmp(1) # => nil
4480 *
4481 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4482 */
4483
4484VALUE
4485rb_str_casecmp(VALUE str1, VALUE str2)
4486{
4487 VALUE s = rb_check_string_type(str2);
4488 if (NIL_P(s)) {
4489 return Qnil;
4490 }
4491 return str_casecmp(str1, s);
4492}
4493
4494static VALUE
4495str_casecmp(VALUE str1, VALUE str2)
4496{
4497 rb_len_t len;
4498 rb_encoding *enc;
4499 const char *p1, *p1end, *p2, *p2end;
4500
4501 enc = rb_enc_compatible(str1, str2);
4502 if (!enc) {
4503 return Qnil;
4504 }
4505
4506 p1 = RSTRING_PTR(str1); p1end = RSTRING_END(str1);
4507 p2 = RSTRING_PTR(str2); p2end = RSTRING_END(str2);
4508 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4509 while (p1 < p1end && p2 < p2end) {
4510 if (*p1 != *p2) {
4511 unsigned int c1 = TOLOWER(*p1 & 0xff);
4512 unsigned int c2 = TOLOWER(*p2 & 0xff);
4513 if (c1 != c2)
4514 return INT2FIX(c1 < c2 ? -1 : 1);
4515 }
4516 p1++;
4517 p2++;
4518 }
4519 }
4520 else {
4521 while (p1 < p1end && p2 < p2end) {
4522 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4523 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4524
4525 if (0 <= c1 && 0 <= c2) {
4526 c1 = TOLOWER(c1);
4527 c2 = TOLOWER(c2);
4528 if (c1 != c2)
4529 return INT2FIX(c1 < c2 ? -1 : 1);
4530 }
4531 else {
4532 int r;
4533 l1 = rb_enc_mbclen(p1, p1end, enc);
4534 l2 = rb_enc_mbclen(p2, p2end, enc);
4535 len = l1 < l2 ? l1 : l2;
4536 r = memcmp(p1, p2, len);
4537 if (r != 0)
4538 return INT2FIX(r < 0 ? -1 : 1);
4539 if (l1 != l2)
4540 return INT2FIX(l1 < l2 ? -1 : 1);
4541 }
4542 p1 += l1;
4543 p2 += l2;
4544 }
4545 }
4546 if (p1 == p1end && p2 == p2end) return INT2FIX(0);
4547 if (p1 == p1end) return INT2FIX(-1);
4548 return INT2FIX(1);
4549}
4550
4551/*
4552 * call-seq:
4553 * casecmp?(other_string) -> true, false, or nil
4554 *
4555 * Returns +true+ if +self+ and +other_string+ are equal after
4556 * Unicode case folding, +false+ if unequal, +nil+ if incomparable.
4557 *
4558 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4559 *
4560 * Examples:
4561 *
4562 * 'foo'.casecmp?('goo') # => false
4563 * 'goo'.casecmp?('foo') # => false
4564 * 'foo'.casecmp?('food') # => false
4565 * 'food'.casecmp?('foo') # => false
4566 * 'FOO'.casecmp?('foo') # => true
4567 * 'foo'.casecmp?('FOO') # => true
4568 * 'foo'.casecmp?(1) # => nil
4569 *
4570 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4571 */
4572
4573static VALUE
4574rb_str_casecmp_p(VALUE str1, VALUE str2)
4575{
4576 VALUE s = rb_check_string_type(str2);
4577 if (NIL_P(s)) {
4578 return Qnil;
4579 }
4580 return str_casecmp_p(str1, s);
4581}
4582
4583static VALUE
4584str_casecmp_p(VALUE str1, VALUE str2)
4585{
4586 rb_encoding *enc;
4587 VALUE folded_str1, folded_str2;
4588 VALUE fold_opt = sym_fold;
4589
4590 enc = rb_enc_compatible(str1, str2);
4591 if (!enc) {
4592 return Qnil;
4593 }
4594
4595 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4596 if (RSTRING_LEN(str1) != RSTRING_LEN(str2)) return Qfalse;
4597 const char *p1 = RSTRING_PTR(str1), *p1end = RSTRING_END(str1);
4598 const char *p2 = RSTRING_PTR(str2);
4599 while (p1 < p1end) {
4600 if (*p1 != *p2 && TOLOWER((unsigned char)*p1) != TOLOWER((unsigned char)*p2)) {
4601 return Qfalse;
4602 }
4603 p1++;
4604 p2++;
4605 }
4606 return Qtrue;
4607 }
4608
4609 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4610 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4611
4612 return rb_str_eql(folded_str1, folded_str2);
4613}
4614
4615static rb_len_t
4616strseq_core(const char *str_ptr, const char *str_ptr_end, rb_len_t str_len,
4617 const char *sub_ptr, rb_len_t sub_len, rb_len_t offset, rb_encoding *enc)
4618{
4619 const char *search_start = str_ptr;
4620 rb_len_t pos, search_len = str_len - offset;
4621
4622 for (;;) {
4623 const char *t;
4624 pos = rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4625 if (pos < 0) return pos;
4626 t = rb_enc_right_char_head(search_start, search_start+pos, str_ptr_end, enc);
4627 if (t == search_start + pos) break;
4628 search_len -= t - search_start;
4629 if (search_len <= 0) return -1;
4630 offset += t - search_start;
4631 search_start = t;
4632 }
4633 return pos + offset;
4634}
4635
4636/* found index in byte */
4637#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4638#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4639
4640static rb_len_t
4641rb_strseq_index(VALUE str, VALUE sub, rb_len_t offset, int in_byte)
4642{
4643 const char *str_ptr, *str_ptr_end, *sub_ptr;
4644 rb_len_t str_len, sub_len;
4645 rb_encoding *enc;
4646
4647 enc = rb_enc_check(str, sub);
4648 if (is_broken_string(sub)) return -1;
4649
4650 str_ptr = RSTRING_PTR(str);
4651 str_ptr_end = RSTRING_END(str);
4652 str_len = RSTRING_LEN(str);
4653 sub_ptr = RSTRING_PTR(sub);
4654 sub_len = RSTRING_LEN(sub);
4655
4656 if (str_len < sub_len) return -1;
4657
4658 if (offset != 0) {
4659 rb_len_t str_len_char, sub_len_char;
4660 int single_byte = single_byte_optimizable(str);
4661 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4662 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4663 if (offset < 0) {
4664 offset += str_len_char;
4665 if (offset < 0) return -1;
4666 }
4667 if (str_len_char - offset < sub_len_char) return -1;
4668 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4669 str_ptr += offset;
4670 }
4671 if (sub_len == 0) return offset;
4672
4673 /* need proceed one character at a time */
4674 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4675}
4676
4677
4678/*
4679 * call-seq:
4680 * index(pattern, offset = 0) -> integer or nil
4681 *
4682 * :include: doc/string/index.rdoc
4683 *
4684 */
4685
4686static VALUE
4687rb_str_index_m(int argc, VALUE *argv, VALUE str)
4688{
4689 VALUE sub;
4690 VALUE initpos;
4691 rb_encoding *enc = STR_ENC_GET(str);
4692 rb_len_t pos;
4693
4694 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4695 rb_len_t slen = str_strlen(str, enc); /* str's enc */
4696 pos = NUM2LEN(initpos);
4697 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4698 if (RB_TYPE_P(sub, T_REGEXP)) {
4700 }
4701 return Qnil;
4702 }
4703 }
4704 else {
4705 pos = 0;
4706 }
4707
4708 if (RB_TYPE_P(sub, T_REGEXP)) {
4709 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4710 enc, single_byte_optimizable(str));
4711
4712 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4713 VALUE match = rb_backref_get();
4714 pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
4715 return LEN2NUM(pos);
4716 }
4717 }
4718 else {
4719 StringValue(sub);
4720 pos = rb_str_index(str, sub, pos);
4721 if (pos >= 0) {
4722 pos = rb_str_sublen(str, pos);
4723 return LEN2NUM(pos);
4724 }
4725 }
4726 return Qnil;
4727}
4728
4729/* Ensure that the given pos is a valid character boundary.
4730 * Note that in this function, "character" means a code point
4731 * (Unicode scalar value), not a grapheme cluster.
4732 */
4733static void
4734str_ensure_byte_pos(VALUE str, rb_len_t pos)
4735{
4736 if (!single_byte_optimizable(str)) {
4737 const char *s = RSTRING_PTR(str);
4738 const char *e = RSTRING_END(str);
4739 const char *p = s + pos;
4740 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4741 rb_raise(rb_eIndexError,
4742 "offset %"PRIdLEN" does not land on character boundary", pos);
4743 }
4744 }
4745}
4746
4747/*
4748 * call-seq:
4749 * byteindex(object, offset = 0) -> integer or nil
4750 *
4751 * Returns the 0-based integer index of a substring of +self+
4752 * specified by +object+ (a string or Regexp) and +offset+,
4753 * or +nil+ if there is no such substring;
4754 * the returned index is the count of _bytes_ (not characters).
4755 *
4756 * When +object+ is a string,
4757 * returns the index of the first found substring equal to +object+:
4758 *
4759 * s = 'foo' # => "foo"
4760 * s.size # => 3 # Three 1-byte characters.
4761 * s.bytesize # => 3 # Three bytes.
4762 * s.byteindex('f') # => 0
4763 * s.byteindex('o') # => 1
4764 * s.byteindex('oo') # => 1
4765 * s.byteindex('ooo') # => nil
4766 *
4767 * When +object+ is a Regexp,
4768 * returns the index of the first found substring matching +object+;
4769 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
4770 *
4771 * s = 'foo'
4772 * s.byteindex(/f/) # => 0
4773 * $~ # => #<MatchData "f">
4774 * s.byteindex(/o/) # => 1
4775 * s.byteindex(/oo/) # => 1
4776 * s.byteindex(/ooo/) # => nil
4777 * $~ # => nil
4778 *
4779 * \Integer argument +offset+, if given, specifies the 0-based index
4780 * of the byte where searching is to begin.
4781 *
4782 * When +offset+ is non-negative,
4783 * searching begins at byte position +offset+:
4784 *
4785 * s = 'foo'
4786 * s.byteindex('o', 1) # => 1
4787 * s.byteindex('o', 2) # => 2
4788 * s.byteindex('o', 3) # => nil
4789 *
4790 * When +offset+ is negative, counts backward from the end of +self+:
4791 *
4792 * s = 'foo'
4793 * s.byteindex('o', -1) # => 2
4794 * s.byteindex('o', -2) # => 1
4795 * s.byteindex('o', -3) # => 1
4796 * s.byteindex('o', -4) # => nil
4797 *
4798 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
4799 *
4800 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
4801 * s.size # => 2 # Two 3-byte characters.
4802 * s.bytesize # => 6 # Six bytes.
4803 * s.byteindex("\uFFFF") # => 0
4804 * s.byteindex("\uFFFF", 1) # Raises IndexError
4805 * s.byteindex("\uFFFF", 2) # Raises IndexError
4806 * s.byteindex("\uFFFF", 3) # => 3
4807 * s.byteindex("\uFFFF", 4) # Raises IndexError
4808 * s.byteindex("\uFFFF", 5) # Raises IndexError
4809 * s.byteindex("\uFFFF", 6) # => nil
4810 *
4811 * Related: see {Querying}[rdoc-ref:String@Querying].
4812 */
4813
4814static VALUE
4815rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
4816{
4817 VALUE sub;
4818 VALUE initpos;
4819 rb_len_t pos;
4820
4821 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4822 pos = NUM2LEN(initpos);
4823 rb_len_t slen = RSTRING_LEN(str);
4824 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4825 if (RB_TYPE_P(sub, T_REGEXP)) {
4827 }
4828 return Qnil;
4829 }
4830 }
4831 else {
4832 pos = 0;
4833 }
4834
4835 str_ensure_byte_pos(str, pos);
4836
4837 if (RB_TYPE_P(sub, T_REGEXP)) {
4838 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4839 VALUE match = rb_backref_get();
4840 pos = RMATCH_BEG(match, 0);
4841 return LEN2NUM(pos);
4842 }
4843 }
4844 else {
4845 StringValue(sub);
4846 pos = rb_str_byteindex(str, sub, pos);
4847 if (pos >= 0) return LEN2NUM(pos);
4848 }
4849 return Qnil;
4850}
4851
4852static rb_len_t
4853str_rindex(VALUE str, VALUE sub, const char *s, rb_encoding *enc)
4854{
4855 const char *hit, *adjusted, *sbeg, *e, *t;
4856 int c;
4857 rb_len_t slen, searchlen;
4858
4859 sbeg = RSTRING_PTR(str);
4860 slen = RSTRING_LEN(sub);
4861 if (slen == 0) return s - sbeg;
4862 e = RSTRING_END(str);
4863 t = RSTRING_PTR(sub);
4864 c = *t & 0xff;
4865 searchlen = s - sbeg + 1;
4866
4867 if (s + slen <= e && memcmp(s, t, slen) == 0) {
4868 return s - sbeg;
4869 }
4870
4871 do {
4872 hit = memrchr(sbeg, c, searchlen);
4873 if (!hit) break;
4874 adjusted = rb_enc_left_char_head(sbeg, hit, e, enc);
4875 if (hit != adjusted) {
4876 searchlen = adjusted - sbeg;
4877 continue;
4878 }
4879 if (hit + slen <= e && memcmp(hit, t, slen) == 0)
4880 return hit - sbeg;
4881 searchlen = adjusted - sbeg;
4882 } while (searchlen > 0);
4883
4884 return -1;
4885}
4886
4887/* found index in byte */
4888static rb_len_t
4889rb_str_rindex(VALUE str, VALUE sub, rb_len_t pos)
4890{
4891 rb_len_t len, slen;
4892 const char *sbeg, *s;
4893 rb_encoding *enc;
4894 int singlebyte;
4895
4896 enc = rb_enc_check(str, sub);
4897 if (is_broken_string(sub)) return -1;
4898 singlebyte = single_byte_optimizable(str);
4899 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc); /* rb_enc_check */
4900 slen = str_strlen(sub, enc); /* rb_enc_check */
4901
4902 /* substring longer than string */
4903 if (len < slen) return -1;
4904 /* character counts, so the byte tail can still be shorter than sub */
4905 if (len - pos < slen) pos = len - slen;
4906 if (len == 0) return pos;
4907
4908 sbeg = RSTRING_PTR(str);
4909
4910 if (pos == 0) {
4911 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4912 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4913 return 0;
4914 }
4915 else {
4916 return -1;
4917 }
4918 }
4919
4920 s = str_nth(sbeg, RSTRING_END(str), pos, enc, singlebyte);
4921 return str_rindex(str, sub, s, enc);
4922}
4923
4924/*
4925 * call-seq:
4926 * rindex(pattern, offset = self.length) -> integer or nil
4927 *
4928 * :include:doc/string/rindex.rdoc
4929 *
4930 */
4931
4932static VALUE
4933rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
4934{
4935 VALUE sub;
4936 VALUE initpos;
4937 rb_encoding *enc = STR_ENC_GET(str);
4938 rb_len_t pos, len = str_strlen(str, enc); /* str's enc */
4939
4940 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4941 pos = NUM2LEN(initpos);
4942 if (pos < 0 && (pos += len) < 0) {
4943 if (RB_TYPE_P(sub, T_REGEXP)) {
4945 }
4946 return Qnil;
4947 }
4948 if (pos > len) pos = len;
4949 }
4950 else {
4951 pos = len;
4952 }
4953
4954 if (RB_TYPE_P(sub, T_REGEXP)) {
4955 /* enc = rb_enc_check(str, sub); */
4956 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4957 enc, single_byte_optimizable(str));
4958
4959 if (rb_reg_search(sub, str, pos, 1) >= 0) {
4960 VALUE match = rb_backref_get();
4961 pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
4962 return LEN2NUM(pos);
4963 }
4964 }
4965 else {
4966 StringValue(sub);
4967 pos = rb_str_rindex(str, sub, pos);
4968 if (pos >= 0) {
4969 pos = rb_str_sublen(str, pos);
4970 return LEN2NUM(pos);
4971 }
4972 }
4973 return Qnil;
4974}
4975
4976static rb_len_t
4977rb_str_byterindex(VALUE str, VALUE sub, rb_len_t pos)
4978{
4979 rb_len_t len, slen;
4980 const char *sbeg, *s;
4981 rb_encoding *enc;
4982
4983 enc = rb_enc_check(str, sub);
4984 if (is_broken_string(sub)) return -1;
4985 len = RSTRING_LEN(str);
4986 slen = RSTRING_LEN(sub);
4987
4988 /* substring longer than string */
4989 if (len < slen) return -1;
4990 if (len - pos < slen) pos = len - slen;
4991 if (len == 0) return pos;
4992
4993 sbeg = RSTRING_PTR(str);
4994
4995 if (pos == 0) {
4996 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4997 return 0;
4998 else
4999 return -1;
5000 }
5001
5002 s = sbeg + pos;
5003 return str_rindex(str, sub, s, enc);
5004}
5005
5006/*
5007 * call-seq:
5008 * byterindex(object, offset = self.bytesize) -> integer or nil
5009 *
5010 * Returns the 0-based integer index of a substring of +self+
5011 * that is the _last_ match for the given +object+ (a string or Regexp) and +offset+,
5012 * or +nil+ if there is no such substring;
5013 * the returned index is the count of _bytes_ (not characters).
5014 *
5015 * When +object+ is a string,
5016 * returns the index of the _last_ found substring equal to +object+:
5017 *
5018 * s = 'foo' # => "foo"
5019 * s.size # => 3 # Three 1-byte characters.
5020 * s.bytesize # => 3 # Three bytes.
5021 * s.byterindex('f') # => 0
5022 * s.byterindex('o') # => 2
5023 * s.byterindex('oo') # => 1
5024 * s.byterindex('ooo') # => nil
5025 *
5026 * When +object+ is a Regexp,
5027 * returns the index of the last found substring matching +object+;
5028 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
5029 *
5030 * s = 'foo'
5031 * s.byterindex(/f/) # => 0
5032 * $~ # => #<MatchData "f">
5033 * s.byterindex(/o/) # => 2
5034 * s.byterindex(/oo/) # => 1
5035 * s.byterindex(/ooo/) # => nil
5036 * $~ # => nil
5037 *
5038 * The last match means starting at the possible last position,
5039 * not the last of the longest matches:
5040 *
5041 * s = 'foo'
5042 * s.byterindex(/o+/) # => 2
5043 * $~ #=> #<MatchData "o">
5044 *
5045 * To get the last longest match, use a negative lookbehind:
5046 *
5047 * s = 'foo'
5048 * s.byterindex(/(?<!o)o+/) # => 1
5049 * $~ # => #<MatchData "oo">
5050 *
5051 * Or use method #byteindex with negative lookahead:
5052 *
5053 * s = 'foo'
5054 * s.byteindex(/o+(?!.*o)/) # => 1
5055 * $~ #=> #<MatchData "oo">
5056 *
5057 * \Integer argument +offset+, if given, specifies the 0-based index
5058 * of the byte where searching is to end.
5059 *
5060 * When +offset+ is non-negative,
5061 * searching ends at byte position +offset+:
5062 *
5063 * s = 'foo'
5064 * s.byterindex('o', 0) # => nil
5065 * s.byterindex('o', 1) # => 1
5066 * s.byterindex('o', 2) # => 2
5067 * s.byterindex('o', 3) # => 2
5068 *
5069 * When +offset+ is negative, counts backward from the end of +self+:
5070 *
5071 * s = 'foo'
5072 * s.byterindex('o', -1) # => 2
5073 * s.byterindex('o', -2) # => 1
5074 * s.byterindex('o', -3) # => nil
5075 *
5076 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
5077 *
5078 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
5079 * s.size # => 2 # Two 3-byte characters.
5080 * s.bytesize # => 6 # Six bytes.
5081 * s.byterindex("\uFFFF") # => 3
5082 * s.byterindex("\uFFFF", 1) # Raises IndexError
5083 * s.byterindex("\uFFFF", 2) # Raises IndexError
5084 * s.byterindex("\uFFFF", 3) # => 3
5085 * s.byterindex("\uFFFF", 4) # Raises IndexError
5086 * s.byterindex("\uFFFF", 5) # Raises IndexError
5087 * s.byterindex("\uFFFF", 6) # => nil
5088 *
5089 * Related: see {Querying}[rdoc-ref:String@Querying].
5090 */
5091
5092static VALUE
5093rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
5094{
5095 VALUE sub;
5096 VALUE initpos;
5097 rb_len_t pos;
5098
5099 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
5100 pos = NUM2LEN(initpos);
5101 rb_len_t len = RSTRING_LEN(str);
5102 if (pos < 0 && (pos += len) < 0) {
5103 if (RB_TYPE_P(sub, T_REGEXP)) {
5105 }
5106 return Qnil;
5107 }
5108 if (pos > len) pos = len;
5109 }
5110 else {
5111 pos = RSTRING_LEN(str);
5112 }
5113
5114 str_ensure_byte_pos(str, pos);
5115
5116 if (RB_TYPE_P(sub, T_REGEXP)) {
5117 if (rb_reg_search(sub, str, pos, 1) >= 0) {
5118 VALUE match = rb_backref_get();
5119 pos = RMATCH_BEG(match, 0);
5120 return LEN2NUM(pos);
5121 }
5122 }
5123 else {
5124 StringValue(sub);
5125 pos = rb_str_byterindex(str, sub, pos);
5126 if (pos >= 0) return LEN2NUM(pos);
5127 }
5128 return Qnil;
5129}
5130
5131/*
5132 * call-seq:
5133 * self =~ other -> integer or nil
5134 *
5135 * When +other+ is a Regexp:
5136 *
5137 * - Returns the integer index (in characters) of the first match
5138 * for +self+ and +other+, or +nil+ if none;
5139 * - Updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
5140 *
5141 * Examples:
5142 *
5143 * 'foo' =~ /f/ # => 0
5144 * $~ # => #<MatchData "f">
5145 * 'foo' =~ /o/ # => 1
5146 * $~ # => #<MatchData "o">
5147 * 'foo' =~ /x/ # => nil
5148 * $~ # => nil
5149 *
5150 * Note that <tt>string =~ regexp</tt> is different from <tt>regexp =~ string</tt>
5151 * (see Regexp#=~):
5152 *
5153 * number = nil
5154 * 'no. 9' =~ /(?<number>\d+)/ # => 4
5155 * number # => nil # Not assigned.
5156 * /(?<number>\d+)/ =~ 'no. 9' # => 4
5157 * number # => "9" # Assigned.
5158 *
5159 * When +other+ is not a Regexp, returns the value
5160 * returned by <tt>other =~ self</tt>.
5161 *
5162 * Related: see {Querying}[rdoc-ref:String@Querying].
5163 */
5164
5165static VALUE
5166rb_str_match(VALUE x, VALUE y)
5167{
5168 switch (OBJ_BUILTIN_TYPE(y)) {
5169 case T_STRING:
5170 rb_raise(rb_eTypeError, "type mismatch: String given");
5171
5172 case T_REGEXP:
5173 return rb_reg_match(y, x);
5174
5175 default:
5176 return rb_funcall(y, idEqTilde, 1, x);
5177 }
5178}
5179
5180
5181static VALUE get_pat(VALUE);
5182
5183
5184/*
5185 * call-seq:
5186 * match(pattern, offset = 0) -> matchdata or nil
5187 * match(pattern, offset = 0) {|matchdata| ... } -> object
5188 *
5189 * Creates a MatchData object based on +self+ and the given arguments;
5190 * updates {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5191 *
5192 * - Computes +regexp+ by converting +pattern+ (if not already a Regexp).
5193 *
5194 * regexp = Regexp.new(pattern)
5195 *
5196 * - Calls <tt>regexp.match</tt> with +self+ to compute +matchdata+.
5197 * If +offset+ is given, it is also passed (see Regexp#match).
5198 *
5199 * With no block given, returns the computed +matchdata+ or +nil+:
5200 *
5201 * 'foo'.match('f') # => #<MatchData "f">
5202 * 'foo'.match('o') # => #<MatchData "o">
5203 * 'foo'.match('x') # => nil
5204 * 'foo'.match('f', 1) # => nil
5205 * 'foo'.match('o', 1) # => #<MatchData "o">
5206 *
5207 * With a block given and computed +matchdata+ non-nil, calls the block with +matchdata+;
5208 * returns the block's return value:
5209 *
5210 * 'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
5211 *
5212 * With a block given and +nil+ +matchdata+, does not call the block:
5213 *
5214 * 'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => nil
5215 *
5216 * Related: see {Querying}[rdoc-ref:String@Querying].
5217 */
5218
5219static VALUE
5220rb_str_match_m(int argc, VALUE *argv, VALUE str)
5221{
5222 VALUE re, result;
5223 if (argc < 1)
5224 rb_check_arity(argc, 1, 2);
5225 re = argv[0];
5226 argv[0] = str;
5227 result = rb_funcallv(get_pat(re), rb_intern("match"), argc, argv);
5228 if (!NIL_P(result) && rb_block_given_p()) {
5229 return rb_yield(result);
5230 }
5231 return result;
5232}
5233
5234/*
5235 * call-seq:
5236 * match?(pattern, offset = 0) -> true or false
5237 *
5238 * Returns whether a match is found for +self+ and the given arguments;
5239 * does not update {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5240 *
5241 * Computes +regexp+ by converting +pattern+ (if not already a Regexp):
5242 *
5243 * regexp = Regexp.new(pattern)
5244 *
5245 * The search for +regexp+ in +self+ begins at the given character +offset+.
5246 * Returns +true+ if a match is found, +false+ otherwise:
5247 *
5248 * 'foo'.match?(/o/) # => true
5249 * 'foo'.match?('o') # => true
5250 * 'foo'.match?(/x/) # => false
5251 * 'foo'.match?('f', 1) # => false
5252 * 'foo'.match?('o', 1) # => true
5253 *
5254 * Related: see {Querying}[rdoc-ref:String@Querying].
5255 */
5256
5257static VALUE
5258rb_str_match_m_p(int argc, VALUE *argv, VALUE str)
5259{
5260 VALUE re;
5261 rb_check_arity(argc, 1, 2);
5262 re = get_pat(argv[0]);
5263 return rb_reg_match_p(re, str, argc > 1 ? NUM2LEN(argv[1]) : 0);
5264}
5265
5266enum neighbor_char {
5267 NEIGHBOR_NOT_CHAR,
5268 NEIGHBOR_FOUND,
5269 NEIGHBOR_WRAPPED
5270};
5271
5272static enum neighbor_char
5273enc_succ_char(char *p, rb_len_t len, rb_encoding *enc)
5274{
5275 rb_len_t i;
5276 int l;
5277
5278 if (rb_enc_mbminlen(enc) > 1) {
5279 /* wchar, trivial case */
5280 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5281 if (!MBCLEN_CHARFOUND_P(r)) {
5282 return NEIGHBOR_NOT_CHAR;
5283 }
5284 c = rb_enc_mbc_to_codepoint(p, p + len, enc) + 1;
5285 l = rb_enc_code_to_mbclen(c, enc);
5286 if (!l) return NEIGHBOR_NOT_CHAR;
5287 if (l != len) return NEIGHBOR_WRAPPED;
5288 rb_enc_mbcput(c, p, enc);
5289 r = rb_enc_precise_mbclen(p, p + len, enc);
5290 if (!MBCLEN_CHARFOUND_P(r)) {
5291 return NEIGHBOR_NOT_CHAR;
5292 }
5293 return NEIGHBOR_FOUND;
5294 }
5295 while (1) {
5296 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0xff; i--)
5297 p[i] = '\0';
5298 if (i < 0)
5299 return NEIGHBOR_WRAPPED;
5300 ++((unsigned char*)p)[i];
5301 l = rb_enc_precise_mbclen(p, p+len, enc);
5302 if (MBCLEN_CHARFOUND_P(l)) {
5303 l = MBCLEN_CHARFOUND_LEN(l);
5304 if (l == len) {
5305 return NEIGHBOR_FOUND;
5306 }
5307 else {
5308 memset(p+l, 0xff, len-l);
5309 }
5310 }
5311 if (MBCLEN_INVALID_P(l) && i < len-1) {
5312 rb_len_t len2;
5313 int l2;
5314 for (len2 = len-1; 0 < len2; len2--) {
5315 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5316 if (!MBCLEN_INVALID_P(l2))
5317 break;
5318 }
5319 memset(p+len2+1, 0xff, len-(len2+1));
5320 }
5321 }
5322}
5323
5324static enum neighbor_char
5325enc_pred_char(char *p, rb_len_t len, rb_encoding *enc)
5326{
5327 rb_len_t i;
5328 int l;
5329 if (rb_enc_mbminlen(enc) > 1) {
5330 /* wchar, trivial case */
5331 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5332 if (!MBCLEN_CHARFOUND_P(r)) {
5333 return NEIGHBOR_NOT_CHAR;
5334 }
5335 c = rb_enc_mbc_to_codepoint(p, p + len, enc);
5336 if (!c) return NEIGHBOR_NOT_CHAR;
5337 --c;
5338 l = rb_enc_code_to_mbclen(c, enc);
5339 if (!l) return NEIGHBOR_NOT_CHAR;
5340 if (l != len) return NEIGHBOR_WRAPPED;
5341 rb_enc_mbcput(c, p, enc);
5342 r = rb_enc_precise_mbclen(p, p + len, enc);
5343 if (!MBCLEN_CHARFOUND_P(r)) {
5344 return NEIGHBOR_NOT_CHAR;
5345 }
5346 return NEIGHBOR_FOUND;
5347 }
5348 while (1) {
5349 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0; i--)
5350 p[i] = '\xff';
5351 if (i < 0)
5352 return NEIGHBOR_WRAPPED;
5353 --((unsigned char*)p)[i];
5354 l = rb_enc_precise_mbclen(p, p+len, enc);
5355 if (MBCLEN_CHARFOUND_P(l)) {
5356 l = MBCLEN_CHARFOUND_LEN(l);
5357 if (l == len) {
5358 return NEIGHBOR_FOUND;
5359 }
5360 else {
5361 memset(p+l, 0, len-l);
5362 }
5363 }
5364 if (MBCLEN_INVALID_P(l) && i < len-1) {
5365 rb_len_t len2;
5366 int l2;
5367 for (len2 = len-1; 0 < len2; len2--) {
5368 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5369 if (!MBCLEN_INVALID_P(l2))
5370 break;
5371 }
5372 memset(p+len2+1, 0, len-(len2+1));
5373 }
5374 }
5375}
5376
5377/*
5378 overwrite +p+ by succeeding letter in +enc+ and returns
5379 NEIGHBOR_FOUND or NEIGHBOR_WRAPPED.
5380 When NEIGHBOR_WRAPPED, carried-out letter is stored into carry.
5381 assuming each ranges are successive, and mbclen
5382 never change in each ranges.
5383 NEIGHBOR_NOT_CHAR is returned if invalid character or the range has only one
5384 character.
5385 */
5386static enum neighbor_char
5387enc_succ_alnum_char(char *p, rb_len_t len, rb_encoding *enc, char *carry)
5388{
5389 enum neighbor_char ret;
5390 unsigned int c;
5391 int ctype;
5392 int range;
5393 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5394
5395 /* skip 03A2, invalid char between GREEK CAPITAL LETTERS */
5396 int try;
5397 const int max_gaps = 1;
5398
5399 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5400 if (rb_enc_isctype(c, ONIGENC_CTYPE_DIGIT, enc))
5401 ctype = ONIGENC_CTYPE_DIGIT;
5402 else if (rb_enc_isctype(c, ONIGENC_CTYPE_ALPHA, enc))
5403 ctype = ONIGENC_CTYPE_ALPHA;
5404 else
5405 return NEIGHBOR_NOT_CHAR;
5406
5407 MEMCPY(save, p, char, len);
5408 for (try = 0; try <= max_gaps; ++try) {
5409 ret = enc_succ_char(p, len, enc);
5410 if (ret == NEIGHBOR_FOUND) {
5411 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5412 if (rb_enc_isctype(c, ctype, enc))
5413 return NEIGHBOR_FOUND;
5414 }
5415 }
5416 MEMCPY(p, save, char, len);
5417 range = 1;
5418 while (1) {
5419 MEMCPY(save, p, char, len);
5420 ret = enc_pred_char(p, len, enc);
5421 if (ret == NEIGHBOR_FOUND) {
5422 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5423 if (!rb_enc_isctype(c, ctype, enc)) {
5424 MEMCPY(p, save, char, len);
5425 break;
5426 }
5427 }
5428 else {
5429 MEMCPY(p, save, char, len);
5430 break;
5431 }
5432 range++;
5433 }
5434 if (range == 1) {
5435 return NEIGHBOR_NOT_CHAR;
5436 }
5437
5438 if (ctype != ONIGENC_CTYPE_DIGIT) {
5439 MEMCPY(carry, p, char, len);
5440 return NEIGHBOR_WRAPPED;
5441 }
5442
5443 MEMCPY(carry, p, char, len);
5444 enc_succ_char(carry, len, enc);
5445 return NEIGHBOR_WRAPPED;
5446}
5447
5448
5449static VALUE str_succ(VALUE str);
5450
5451/*
5452 * call-seq:
5453 * succ -> new_str
5454 *
5455 * :include: doc/string/succ.rdoc
5456 *
5457 */
5458
5459VALUE
5461{
5462 VALUE str;
5463 str = rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5464 rb_enc_cr_str_copy_for_substr(str, orig);
5465 return str_succ(str);
5466}
5467
5468static VALUE
5469str_succ(VALUE str)
5470{
5471 rb_encoding *enc;
5472 char *sbeg, *s, *e, *last_alnum = 0;
5473 int found_alnum = 0;
5474 rb_len_t l, slen;
5475 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] = "\1";
5476 rb_len_t carry_pos = 0, carry_len = 1;
5477 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5478
5479 slen = RSTRING_LEN(str);
5480 if (slen == 0) return str;
5481
5482 enc = STR_ENC_GET(str);
5483 sbeg = RSTRING_PTR(str);
5484 s = e = sbeg + slen;
5485
5486 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5487 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5488 if (ISALPHA(*last_alnum) ? ISDIGIT(*s) :
5489 ISDIGIT(*last_alnum) ? ISALPHA(*s) : 0) {
5490 break;
5491 }
5492 }
5493 l = rb_enc_precise_mbclen(s, e, enc);
5494 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5495 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5496 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5497 switch (neighbor) {
5498 case NEIGHBOR_NOT_CHAR:
5499 continue;
5500 case NEIGHBOR_FOUND:
5501 return str;
5502 case NEIGHBOR_WRAPPED:
5503 last_alnum = s;
5504 break;
5505 }
5506 found_alnum = 1;
5507 carry_pos = s - sbeg;
5508 carry_len = l;
5509 }
5510 if (!found_alnum) { /* str contains no alnum */
5511 s = e;
5512 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5513 enum neighbor_char neighbor;
5514 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5515 l = rb_enc_precise_mbclen(s, e, enc);
5516 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5517 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5518 MEMCPY(tmp, s, char, l);
5519 neighbor = enc_succ_char(tmp, l, enc);
5520 switch (neighbor) {
5521 case NEIGHBOR_FOUND:
5522 MEMCPY(s, tmp, char, l);
5523 return str;
5524 break;
5525 case NEIGHBOR_WRAPPED:
5526 MEMCPY(s, tmp, char, l);
5527 break;
5528 case NEIGHBOR_NOT_CHAR:
5529 break;
5530 }
5531 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5532 /* wrapped to \0...\0. search next valid char. */
5533 enc_succ_char(s, l, enc);
5534 }
5535 if (!rb_enc_asciicompat(enc)) {
5536 MEMCPY(carry, s, char, l);
5537 carry_len = l;
5538 }
5539 carry_pos = s - sbeg;
5540 }
5542 }
5543 RESIZE_CAPA(str, slen + carry_len);
5544 sbeg = RSTRING_PTR(str);
5545 s = sbeg + carry_pos;
5546 memmove(s + carry_len, s, slen - carry_pos);
5547 memmove(s, carry, carry_len);
5548 slen += carry_len;
5549 STR_SET_LEN(str, slen);
5550 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5551 rb_enc_str_coderange(str);
5552 return str;
5553}
5554
5555
5556/*
5557 * call-seq:
5558 * succ! -> self
5559 *
5560 * Like String#succ, but modifies +self+ in place; returns +self+.
5561 *
5562 * Related: see {Modifying}[rdoc-ref:String@Modifying].
5563 */
5564
5565static VALUE
5566rb_str_succ_bang(VALUE str)
5567{
5568 rb_str_modify(str);
5569 str_succ(str);
5570 return str;
5571}
5572
5573static int
5574all_digits_p(const char *s, rb_len_t len)
5575{
5576 while (len-- > 0) {
5577 if (!ISDIGIT(*s)) return 0;
5578 s++;
5579 }
5580 return 1;
5581}
5582
5583static int
5584str_upto_i(VALUE str, VALUE arg)
5585{
5586 rb_yield(str);
5587 return 0;
5588}
5589
5590/*
5591 * call-seq:
5592 * upto(other_string, exclusive = false) {|string| ... } -> self
5593 * upto(other_string, exclusive = false) -> new_enumerator
5594 *
5595 * :include: doc/string/upto.rdoc
5596 *
5597 */
5598
5599static VALUE
5600rb_str_upto(int argc, VALUE *argv, VALUE beg)
5601{
5602 VALUE end, exclusive;
5603
5604 rb_scan_args(argc, argv, "11", &end, &exclusive);
5605 RETURN_ENUMERATOR(beg, argc, argv);
5606 return rb_str_upto_each(beg, end, RTEST(exclusive), str_upto_i, Qnil);
5607}
5608
5609VALUE
5610rb_str_upto_each(VALUE beg, VALUE end, int excl, int (*each)(VALUE, VALUE), VALUE arg)
5611{
5612 VALUE current, after_end;
5613 ID succ;
5614 int n, ascii;
5615 rb_encoding *enc;
5616
5617 CONST_ID(succ, "succ");
5618 StringValue(end);
5619 enc = rb_enc_check(beg, end);
5620 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5621 /* single character */
5622 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5623 char c = RSTRING_PTR(beg)[0];
5624 char e = RSTRING_PTR(end)[0];
5625
5626 if (c > e || (excl && c == e)) return beg;
5627 for (;;) {
5628 VALUE str = rb_enc_str_new(&c, 1, enc);
5630 if ((*each)(str, arg)) break;
5631 if (!excl && c == e) break;
5632 c++;
5633 if (excl && c == e) break;
5634 }
5635 return beg;
5636 }
5637 /* both edges are all digits */
5638 if (ascii && ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
5639 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5640 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5641 VALUE b, e;
5642 int width;
5643
5644 width = RSTRING_LENINT(beg);
5645 b = rb_str_to_inum(beg, 10, FALSE);
5646 e = rb_str_to_inum(end, 10, FALSE);
5647 if (FIXNUM_P(b) && FIXNUM_P(e)) {
5648 long bi = FIX2LONG(b);
5649 long ei = FIX2LONG(e);
5650 rb_encoding *usascii = rb_usascii_encoding();
5651
5652 while (bi <= ei) {
5653 if (excl && bi == ei) break;
5654 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5655 bi++;
5656 }
5657 }
5658 else {
5659 ID op = excl ? '<' : idLE;
5660 VALUE args[2], fmt = rb_fstring_lit("%.*d");
5661
5662 args[0] = INT2FIX(width);
5663 while (rb_funcall(b, op, 1, e)) {
5664 args[1] = b;
5665 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5666 b = rb_funcallv(b, succ, 0, 0);
5667 }
5668 }
5669 return beg;
5670 }
5671 /* normal case */
5672 n = rb_str_cmp(beg, end);
5673 if (n > 0 || (excl && n == 0)) return beg;
5674
5675 after_end = rb_funcallv(end, succ, 0, 0);
5676 current = str_duplicate(rb_cString, beg);
5677 while (!rb_str_equal(current, after_end)) {
5678 VALUE next = Qnil;
5679 if (excl || !rb_str_equal(current, end))
5680 next = rb_funcallv(current, succ, 0, 0);
5681 if ((*each)(current, arg)) break;
5682 if (NIL_P(next)) break;
5683 current = next;
5684 StringValue(current);
5685 if (excl && rb_str_equal(current, end)) break;
5686 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5687 break;
5688 }
5689
5690 return beg;
5691}
5692
5693VALUE
5694rb_str_upto_endless_each(VALUE beg, int (*each)(VALUE, VALUE), VALUE arg)
5695{
5696 VALUE current;
5697 ID succ;
5698
5699 CONST_ID(succ, "succ");
5700 /* both edges are all digits */
5701 if (is_ascii_string(beg) && ISDIGIT(RSTRING_PTR(beg)[0]) &&
5702 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5703 VALUE b, args[2], fmt = rb_fstring_lit("%.*d");
5704 int width = RSTRING_LENINT(beg);
5705 b = rb_str_to_inum(beg, 10, FALSE);
5706 if (FIXNUM_P(b)) {
5707 long bi = FIX2LONG(b);
5708 rb_encoding *usascii = rb_usascii_encoding();
5709
5710 while (FIXABLE(bi)) {
5711 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5712 bi++;
5713 }
5714 b = LONG2NUM(bi);
5715 }
5716 args[0] = INT2FIX(width);
5717 while (1) {
5718 args[1] = b;
5719 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5720 b = rb_funcallv(b, succ, 0, 0);
5721 }
5722 }
5723 /* normal case */
5724 current = str_duplicate(rb_cString, beg);
5725 while (1) {
5726 VALUE next = rb_funcallv(current, succ, 0, 0);
5727 if ((*each)(current, arg)) break;
5728 current = next;
5729 StringValue(current);
5730 if (RSTRING_LEN(current) == 0)
5731 break;
5732 }
5733
5734 return beg;
5735}
5736
5737static int
5738include_range_i(VALUE str, VALUE arg)
5739{
5740 VALUE *argp = (VALUE *)arg;
5741 if (!rb_equal(str, *argp)) return 0;
5742 *argp = Qnil;
5743 return 1;
5744}
5745
5746VALUE
5747rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive)
5748{
5749 beg = rb_str_new_frozen(beg);
5750 StringValue(end);
5751 end = rb_str_new_frozen(end);
5752 if (NIL_P(val)) return Qfalse;
5753 val = rb_check_string_type(val);
5754 if (NIL_P(val)) return Qfalse;
5755 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5756 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5757 rb_enc_asciicompat(STR_ENC_GET(val))) {
5758 const char *bp = RSTRING_PTR(beg);
5759 const char *ep = RSTRING_PTR(end);
5760 const char *vp = RSTRING_PTR(val);
5761 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5762 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5763 return Qfalse;
5764 else {
5765 char b = *bp;
5766 char e = *ep;
5767 char v = *vp;
5768
5769 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
5770 if (b <= v && v < e) return Qtrue;
5771 return RBOOL(!RTEST(exclusive) && b <= v && v == e);
5772 }
5773 }
5774 }
5775#if 0
5776 /* both edges are all digits */
5777 if (ISDIGIT(*bp) && ISDIGIT(*ep) &&
5778 all_digits_p(bp, RSTRING_LEN(beg)) &&
5779 all_digits_p(ep, RSTRING_LEN(end))) {
5780 /* TODO */
5781 }
5782#endif
5783 }
5784 rb_str_upto_each(beg, end, RTEST(exclusive), include_range_i, (VALUE)&val);
5785
5786 return RBOOL(NIL_P(val));
5787}
5788
5789static VALUE
5790rb_str_subpat(VALUE str, VALUE re, VALUE backref)
5791{
5792 if (rb_reg_search(re, str, 0, 0) >= 0) {
5793 VALUE match = rb_backref_get();
5794 int nth = rb_reg_backref_number(match, backref);
5795 return rb_reg_nth_match(nth, match);
5796 }
5797 return Qnil;
5798}
5799
5800static VALUE
5801rb_str_aref(VALUE str, VALUE indx)
5802{
5803 rb_len_t idx;
5804
5805 if (FIXNUM_P(indx)) {
5806 idx = FIX2LONG(indx);
5807 }
5808 else if (RB_TYPE_P(indx, T_REGEXP)) {
5809 return rb_str_subpat(str, indx, INT2FIX(0));
5810 }
5811 else if (RB_TYPE_P(indx, T_STRING)) {
5812 if (rb_str_index(str, indx, 0) != -1)
5813 return str_duplicate(rb_cString, indx);
5814 return Qnil;
5815 }
5816 else {
5817 /* check if indx is Range */
5818 rb_len_t beg, len = str_strlen(str, NULL);
5819 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
5820 case Qfalse:
5821 break;
5822 case Qnil:
5823 return Qnil;
5824 default:
5825 return rb_str_substr(str, beg, len);
5826 }
5827 idx = NUM2LEN(indx);
5828 }
5829
5830 return str_substr(str, idx, 1, FALSE);
5831}
5832
5833
5834/*
5835 * call-seq:
5836 * self[offset] -> new_string or nil
5837 * self[offset, size] -> new_string or nil
5838 * self[range] -> new_string or nil
5839 * self[regexp, capture = 0] -> new_string or nil
5840 * self[substring] -> new_string or nil
5841 *
5842 * :include: doc/string/aref.rdoc
5843 *
5844 */
5845
5846static VALUE
5847rb_str_aref_m(int argc, VALUE *argv, VALUE str)
5848{
5849 if (argc == 2) {
5850 if (RB_TYPE_P(argv[0], T_REGEXP)) {
5851 return rb_str_subpat(str, argv[0], argv[1]);
5852 }
5853 else {
5854 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5855 }
5856 }
5857 rb_check_arity(argc, 1, 2);
5858 return rb_str_aref(str, argv[0]);
5859}
5860
5861VALUE
5863{
5864 char *ptr = RSTRING_PTR(str);
5865 rb_len_t olen = RSTRING_LEN(str), nlen;
5866
5867 str_modifiable(str);
5868 if (len > olen) len = olen;
5869 nlen = olen - len;
5870 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5871 char *oldptr = ptr;
5872 size_t old_capa = RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5873 int fl = (int)(RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5874 STR_SET_EMBED(str);
5875 ptr = RSTRING(str)->as.embed.ary;
5876 memmove(ptr, oldptr + len, nlen);
5877 if (fl == STR_NOEMBED) {
5878 SIZED_FREE_N(oldptr, old_capa);
5879 }
5880 }
5881 else {
5882 if (!STR_SHARED_P(str)) {
5883 VALUE shared = heap_str_make_shared(rb_obj_class(str), str, TERM_LEN(str));
5884 rb_enc_cr_str_exact_copy(shared, str);
5886 }
5887 ptr = RSTRING(str)->as.heap.ptr += len;
5888 }
5889 STR_SET_LEN(str, nlen);
5890
5891 if (!SHARABLE_MIDDLE_SUBSTRING) {
5892 TERM_FILL(ptr + nlen, TERM_LEN(str));
5893 }
5895 return str;
5896}
5897
5898static void
5899rb_str_update_1(VALUE str, rb_len_t beg, rb_len_t len, VALUE val, rb_len_t vbeg, rb_len_t vlen)
5900{
5901 char *sptr;
5902 rb_len_t slen;
5903 int cr;
5904
5905 if (beg == 0 && vlen == 0) {
5906 rb_str_drop_bytes(str, len);
5907 return;
5908 }
5909
5910 str_modify_keep_cr(str);
5911 RSTRING_GETMEM(str, sptr, slen);
5912 if (len < vlen) {
5913 /* expand string */
5914 RESIZE_CAPA(str, slen + vlen - len);
5915 sptr = RSTRING_PTR(str);
5916 }
5917
5919 cr = rb_enc_str_coderange(val);
5920 else
5922
5923 if (vlen != len) {
5924 memmove(sptr + beg + vlen,
5925 sptr + beg + len,
5926 slen - (beg + len));
5927 }
5928 if (vlen < beg && len < 0) {
5929 MEMZERO(sptr + slen, char, -len);
5930 }
5931 if (vlen > 0) {
5932 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5933 }
5934 slen += vlen - len;
5935 STR_SET_LEN(str, slen);
5936 TERM_FILL(&sptr[slen], TERM_LEN(str));
5937 ENC_CODERANGE_SET(str, cr);
5938}
5939
5940static inline void
5941rb_str_update_0(VALUE str, rb_len_t beg, rb_len_t len, VALUE val)
5942{
5943 rb_str_update_1(str, beg, len, val, 0, RSTRING_LEN(val));
5944}
5945
5946void
5948{
5949 rb_len_t slen;
5950 char *p, *e;
5951 rb_encoding *enc;
5952 int singlebyte = single_byte_optimizable(str);
5953 int cr;
5954
5955 if (len < 0) rb_raise(rb_eIndexError, "negative length %"PRIdLEN, len);
5956
5957 StringValue(val);
5958 enc = rb_enc_check(str, val);
5959 slen = str_strlen(str, enc); /* rb_enc_check */
5960
5961 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5962 rb_raise(rb_eIndexError, "index %"PRIdLEN" out of string", beg);
5963 }
5964 if (beg < 0) {
5965 beg += slen;
5966 }
5967 RUBY_ASSERT(beg >= 0);
5968 RUBY_ASSERT(beg <= slen);
5969
5970 if (len > slen - beg) {
5971 len = slen - beg;
5972 }
5973 p = str_nth(RSTRING_PTR(str), RSTRING_END(str), beg, enc, singlebyte);
5974 if (!p) p = RSTRING_END(str);
5975 e = str_nth(p, RSTRING_END(str), len, enc, singlebyte);
5976 if (!e) e = RSTRING_END(str);
5977 /* error check */
5978 beg = p - RSTRING_PTR(str); /* physical position */
5979 len = e - p; /* physical length */
5980 rb_str_update_0(str, beg, len, val);
5981 rb_enc_associate(str, enc);
5983 if (cr != ENC_CODERANGE_BROKEN)
5984 ENC_CODERANGE_SET(str, cr);
5985}
5986
5987static void
5988rb_str_subpat_set(VALUE str, VALUE re, VALUE backref, VALUE val)
5989{
5990 int nth;
5991 VALUE match;
5992 rb_len_t start, end, len;
5993 rb_encoding *enc;
5994
5995 if (rb_reg_search(re, str, 0, 0) < 0) {
5996 rb_raise(rb_eIndexError, "regexp not matched");
5997 }
5998 match = rb_backref_get();
5999 nth = rb_reg_backref_number(match, backref);
6000 int num_regs = RMATCH_NREGS(match);
6001 if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
6002 rb_raise(rb_eIndexError, "index %d out of regexp", nth);
6003 }
6004 if (nth < 0) {
6005 nth += num_regs;
6006 }
6007
6008 start = RMATCH_BEG(match, nth);
6009 if (start == -1) {
6010 rb_raise(rb_eIndexError, "regexp group %d not matched", nth);
6011 }
6012 end = RMATCH_END(match, nth);
6013 len = end - start;
6014
6015 StringValue(val);
6016 if (start + len > RSTRING_LEN(str)) {
6017 rb_raise(rb_eRuntimeError, "string modified");
6018 }
6019
6020 enc = rb_enc_check_str(str, val);
6021 rb_str_update_0(str, start, len, val);
6022 rb_enc_associate(str, enc);
6023}
6024
6025static VALUE
6026rb_str_aset(VALUE str, VALUE indx, VALUE val)
6027{
6028 rb_len_t idx, beg;
6029
6030 switch (TYPE(indx)) {
6031 case T_REGEXP:
6032 rb_str_subpat_set(str, indx, INT2FIX(0), val);
6033 return val;
6034
6035 case T_STRING:
6036 beg = rb_str_index(str, indx, 0);
6037 if (beg < 0) {
6038 rb_raise(rb_eIndexError, "string not matched");
6039 }
6040 beg = rb_str_sublen(str, beg);
6041 rb_str_update(str, beg, str_strlen(indx, NULL), val);
6042 return val;
6043
6044 default:
6045 /* check if indx is Range */
6046 {
6047 rb_len_t beg, len;
6048 if (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 2)) {
6049 rb_str_update(str, beg, len, val);
6050 return val;
6051 }
6052 }
6053 /* FALLTHROUGH */
6054
6055 case T_FIXNUM:
6056 idx = NUM2LEN(indx);
6057 rb_str_update(str, idx, 1, val);
6058 return val;
6059 }
6060}
6061
6062/*
6063 * call-seq:
6064 * self[index] = other_string -> new_string
6065 * self[start, length] = other_string -> new_string
6066 * self[range] = other_string -> new_string
6067 * self[regexp, capture = 0] = other_string -> new_string
6068 * self[substring] = other_string -> new_string
6069 *
6070 * :include: doc/string/aset.rdoc
6071 *
6072 */
6073
6074static VALUE
6075rb_str_aset_m(int argc, VALUE *argv, VALUE str)
6076{
6077 if (argc == 3) {
6078 if (RB_TYPE_P(argv[0], T_REGEXP)) {
6079 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6080 }
6081 else {
6082 rb_str_update(str, NUM2LEN(argv[0]), NUM2LEN(argv[1]), argv[2]);
6083 }
6084 return argv[2];
6085 }
6086 rb_check_arity(argc, 2, 3);
6087 return rb_str_aset(str, argv[0], argv[1]);
6088}
6089
6090/*
6091 * call-seq:
6092 * insert(offset, other_string) -> self
6093 *
6094 * :include: doc/string/insert.rdoc
6095 *
6096 */
6097
6098static VALUE
6099rb_str_insert(VALUE str, VALUE idx, VALUE str2)
6100{
6101 rb_len_t pos = NUM2LEN(idx);
6102
6103 if (pos == -1) {
6104 return rb_str_append(str, str2);
6105 }
6106 else if (pos < 0) {
6107 pos++;
6108 }
6109 rb_str_update(str, pos, 0, str2);
6110 return str;
6111}
6112
6113
6114/*
6115 * call-seq:
6116 * slice!(index) -> new_string or nil
6117 * slice!(start, length) -> new_string or nil
6118 * slice!(range) -> new_string or nil
6119 * slice!(regexp, capture = 0) -> new_string or nil
6120 * slice!(substring) -> new_string or nil
6121 *
6122 * Like String#[] (and its alias String#slice), except that:
6123 *
6124 * - Performs substitutions in +self+ (not in a copy of +self+).
6125 * - Returns the removed substring if any modifications were made, +nil+ otherwise.
6126 *
6127 * A few examples:
6128 *
6129 * s = 'hello'
6130 * s.slice!('e') # => "e"
6131 * s # => "hllo"
6132 * s.slice!('e') # => nil
6133 * s # => "hllo"
6134 *
6135 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6136 */
6137
6138static VALUE
6139rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
6140{
6141 VALUE result = Qnil;
6142 VALUE indx;
6143 rb_len_t beg, len = 1;
6144 char *p;
6145
6146 rb_check_arity(argc, 1, 2);
6147 str_modify_keep_cr(str);
6148 indx = argv[0];
6149 if (RB_TYPE_P(indx, T_REGEXP)) {
6150 if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
6151 VALUE match = rb_backref_get();
6152 int num_regs = RMATCH_NREGS(match);
6153 int nth = 0;
6154 if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
6155 if ((nth += num_regs) <= 0) return Qnil;
6156 }
6157 else if (nth >= num_regs) return Qnil;
6158 beg = RMATCH_BEG(match, nth);
6159 len = RMATCH_END(match, nth) - beg;
6160 /* Converting the backref may have modified the string. */
6161 if (beg > RSTRING_LEN(str)) return Qnil;
6162 if (len > RSTRING_LEN(str) - beg) len = RSTRING_LEN(str) - beg;
6163 goto subseq;
6164 }
6165 else if (argc == 2) {
6166 beg = NUM2LEN(indx);
6167 len = NUM2LEN(argv[1]);
6168 goto num_index;
6169 }
6170 else if (FIXNUM_P(indx)) {
6171 beg = FIX2LONG(indx);
6172 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6173 if (!len) return Qnil;
6174 beg = p - RSTRING_PTR(str);
6175 goto subseq;
6176 }
6177 else if (RB_TYPE_P(indx, T_STRING)) {
6178 beg = rb_str_index(str, indx, 0);
6179 if (beg == -1) return Qnil;
6180 len = RSTRING_LEN(indx);
6181 result = str_duplicate(rb_cString, indx);
6182 goto squash;
6183 }
6184 else {
6185 switch (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 0)) {
6186 case Qnil:
6187 return Qnil;
6188 case Qfalse:
6189 beg = NUM2LEN(indx);
6190 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6191 if (!len) return Qnil;
6192 beg = p - RSTRING_PTR(str);
6193 goto subseq;
6194 default:
6195 goto num_index;
6196 }
6197 }
6198
6199 num_index:
6200 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6201 beg = p - RSTRING_PTR(str);
6202
6203 subseq:
6204 result = rb_str_new(RSTRING_PTR(str)+beg, len);
6205 rb_enc_cr_str_copy_for_substr(result, str);
6206
6207 squash:
6208 if (len > 0) {
6209 if (beg == 0) {
6210 rb_str_drop_bytes(str, len);
6211 }
6212 else {
6213 char *sptr = RSTRING_PTR(str);
6214 rb_len_t slen = RSTRING_LEN(str);
6215 if (beg + len > slen) /* pathological check */
6216 len = slen - beg;
6217 memmove(sptr + beg,
6218 sptr + beg + len,
6219 slen - (beg + len));
6220 slen -= len;
6221 STR_SET_LEN(str, slen);
6222 TERM_FILL(&sptr[slen], TERM_LEN(str));
6223 }
6224 }
6225 return result;
6226}
6227
6228static VALUE
6229get_pat(VALUE pat)
6230{
6231 VALUE val;
6232
6233 switch (OBJ_BUILTIN_TYPE(pat)) {
6234 case T_REGEXP:
6235 return pat;
6236
6237 case T_STRING:
6238 break;
6239
6240 default:
6241 val = rb_check_string_type(pat);
6242 if (NIL_P(val)) {
6243 Check_Type(pat, T_REGEXP);
6244 }
6245 pat = val;
6246 }
6247
6248 return rb_reg_regcomp(pat);
6249}
6250
6251static VALUE
6252get_pat_quoted(VALUE pat, int check)
6253{
6254 VALUE val;
6255
6256 switch (OBJ_BUILTIN_TYPE(pat)) {
6257 case T_REGEXP:
6258 return pat;
6259
6260 case T_STRING:
6261 break;
6262
6263 default:
6264 val = rb_check_string_type(pat);
6265 if (NIL_P(val)) {
6266 Check_Type(pat, T_REGEXP);
6267 }
6268 pat = val;
6269 }
6270 if (check && is_broken_string(pat)) {
6271 rb_exc_raise(rb_reg_check_preprocess(pat));
6272 }
6273 return pat;
6274}
6275
6276static rb_len_t
6277rb_pat_search0(VALUE pat, VALUE str, rb_len_t pos, int set_backref_str, VALUE *match)
6278{
6279 if (BUILTIN_TYPE(pat) == T_STRING) {
6280 pos = rb_str_byteindex(str, pat, pos);
6281 if (set_backref_str) {
6282 if (pos >= 0) {
6283 str = rb_str_new_frozen_String(str);
6284 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6285 if (match) {
6286 *match = match_data;
6287 }
6288 }
6289 else {
6291 }
6292 }
6293 return pos;
6294 }
6295 else {
6296 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6297 }
6298}
6299
6300static rb_len_t
6301rb_pat_search(VALUE pat, VALUE str, rb_len_t pos, int set_backref_str)
6302{
6303 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6304}
6305
6306
6307/*
6308 * call-seq:
6309 * sub!(pattern, replacement) -> self or nil
6310 * sub!(pattern) {|match| ... } -> self or nil
6311 *
6312 * Like String#sub, except that:
6313 *
6314 * - Changes are made to +self+, not to copy of +self+.
6315 * - Returns +self+ if any changes are made, +nil+ otherwise.
6316 *
6317 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6318 */
6319
6320static VALUE
6321rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
6322{
6323 VALUE pat, repl, hash = Qnil;
6324 int iter = 0;
6325 rb_len_t plen;
6326 int min_arity = rb_block_given_p() ? 1 : 2;
6327 rb_len_t beg;
6328
6329 rb_check_arity(argc, min_arity, 2);
6330 if (argc == 1) {
6331 iter = 1;
6332 }
6333 else {
6334 repl = argv[1];
6335 if (!RB_TYPE_P(repl, T_STRING)) {
6336 hash = rb_check_hash_type(repl);
6337 if (NIL_P(hash)) {
6338 StringValue(repl);
6339 }
6340 }
6341 }
6342
6343 pat = get_pat_quoted(argv[0], 1);
6344
6345 str_modifiable(str);
6346 beg = rb_pat_search(pat, str, 0, 1);
6347 if (beg >= 0) {
6348 rb_encoding *enc;
6349 int cr = ENC_CODERANGE(str);
6350 rb_len_t beg0, end0;
6351 VALUE match, match0 = Qnil;
6352 char *p, *rp;
6353 rb_len_t len, rlen;
6354
6355 match = rb_backref_get();
6356 if (RB_TYPE_P(pat, T_STRING)) {
6357 beg0 = beg;
6358 end0 = beg0 + RSTRING_LEN(pat);
6359 match0 = pat;
6360 }
6361 else {
6362 beg0 = RMATCH_BEG(match, 0);
6363 end0 = RMATCH_END(match, 0);
6364 if (iter) match0 = rb_reg_nth_match(0, match);
6365 }
6366
6367 if (iter || !NIL_P(hash)) {
6368 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6369
6370 if (iter) {
6371 repl = rb_obj_as_string(rb_yield(match0));
6372 }
6373 else {
6374 repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0));
6375 repl = rb_obj_as_string(repl);
6376 }
6377 str_mod_check(str, p, len);
6378 rb_check_frozen(str);
6379 }
6380 else {
6381 repl = rb_reg_regsub_match(repl, str, match);
6382 }
6383
6384 enc = rb_enc_compatible(str, repl);
6385 if (!enc) {
6386 rb_encoding *str_enc = STR_ENC_GET(str);
6387 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6388 if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
6389 coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
6390 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
6391 rb_enc_inspect_name(str_enc),
6392 rb_enc_inspect_name(STR_ENC_GET(repl)));
6393 }
6394 enc = STR_ENC_GET(repl);
6395 }
6396 rb_str_modify(str);
6397 rb_enc_associate(str, enc);
6399 int cr2 = ENC_CODERANGE(repl);
6400 if (cr2 == ENC_CODERANGE_BROKEN ||
6401 (cr == ENC_CODERANGE_VALID && cr2 == ENC_CODERANGE_7BIT))
6403 else
6404 cr = cr2;
6405 }
6406 plen = end0 - beg0;
6407 rlen = RSTRING_LEN(repl);
6408 len = RSTRING_LEN(str);
6409 if (rlen > plen) {
6410 RESIZE_CAPA(str, len + rlen - plen);
6411 }
6412 p = RSTRING_PTR(str);
6413 if (rlen != plen) {
6414 memmove(p + beg0 + rlen, p + beg0 + plen, len - beg0 - plen);
6415 }
6416 rp = RSTRING_PTR(repl);
6417 memmove(p + beg0, rp, rlen);
6418 len += rlen - plen;
6419 STR_SET_LEN(str, len);
6420 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
6421 ENC_CODERANGE_SET(str, cr);
6422
6423 RB_GC_GUARD(match);
6424
6425 return str;
6426 }
6427 return Qnil;
6428}
6429
6430
6431/*
6432 * call-seq:
6433 * sub(pattern, replacement) -> new_string
6434 * sub(pattern) {|match| ... } -> new_string
6435 *
6436 * :include: doc/string/sub.rdoc
6437 */
6438
6439static VALUE
6440rb_str_sub(int argc, VALUE *argv, VALUE str)
6441{
6442 str = str_duplicate(rb_cString, str);
6443 rb_str_sub_bang(argc, argv, str);
6444 return str;
6445}
6446
6447static VALUE
6448str_gsub(int argc, VALUE *argv, VALUE str, int bang)
6449{
6450 VALUE pat, val = Qnil, repl, match0 = Qnil, dest, hash = Qnil, match = Qnil;
6451 rb_len_t beg, beg0, end0;
6452 rb_len_t offset, blen, slen, len, last;
6453 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6454 char *sp, *cp;
6455 int need_backref_str = -1;
6456 rb_encoding *str_enc;
6457
6458 switch (argc) {
6459 case 1:
6460 RETURN_ENUMERATOR(str, argc, argv);
6461 mode = ITER;
6462 break;
6463 case 2:
6464 repl = argv[1];
6465 if (!RB_TYPE_P(repl, T_STRING)) {
6466 hash = rb_check_hash_type(repl);
6467 if (NIL_P(hash)) {
6468 StringValue(repl);
6469 }
6470 else if (rb_hash_default_unredefined(hash) && !FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6471 mode = FAST_MAP;
6472 }
6473 else {
6474 mode = MAP;
6475 }
6476 }
6477 break;
6478 default:
6479 rb_error_arity(argc, 1, 2);
6480 }
6481
6482 pat = get_pat_quoted(argv[0], 1);
6483 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6484
6485 if (beg < 0) {
6486 if (bang) return Qnil; /* no match, no substitution */
6487 return str_duplicate(rb_cString, str);
6488 }
6489 if (bang) str_modify_keep_cr(str);
6490
6491 offset = 0;
6492 blen = RSTRING_LEN(str) + 30; /* len + margin */
6493 dest = rb_str_buf_new(blen);
6494 sp = RSTRING_PTR(str);
6495 slen = RSTRING_LEN(str);
6496 cp = sp;
6497 str_enc = STR_ENC_GET(str);
6498 rb_enc_associate(dest, str_enc);
6499 ENC_CODERANGE_SET(dest, rb_enc_asciicompat(str_enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
6500
6501 do {
6502 if (RB_TYPE_P(pat, T_STRING)) {
6503 beg0 = beg;
6504 end0 = beg0 + RSTRING_LEN(pat);
6505 match0 = pat;
6506 }
6507 else {
6508 beg0 = RMATCH_BEG(match, 0);
6509 end0 = RMATCH_END(match, 0);
6510 if (mode == ITER) match0 = rb_reg_nth_match(0, match);
6511 }
6512
6513 if (mode != STR) {
6514 if (mode == ITER) {
6515 val = rb_obj_as_string(rb_yield(match0));
6516 }
6517 else {
6518 struct RString fake_str = {RBASIC_INIT};
6519 VALUE key;
6520 if (mode == FAST_MAP) {
6521 // It is safe to use a fake_str here because we established that it won't escape,
6522 // as it's only used for `rb_hash_aref` and we checked the hash doesn't have a
6523 // default proc.
6524 key = setup_fake_str(&fake_str, sp + beg0, end0 - beg0, ENCODING_GET_INLINED(str));
6525 }
6526 else {
6527 key = rb_str_subseq(str, beg0, end0 - beg0);
6528 }
6529 val = rb_hash_aref(hash, key);
6530 val = rb_obj_as_string(val);
6531 }
6532 str_mod_check(str, sp, slen);
6533 if (val == dest) { /* paranoid check [ruby-dev:24827] */
6534 rb_raise(rb_eRuntimeError, "block should not cheat");
6535 }
6536 }
6537 else if (need_backref_str) {
6538 val = rb_reg_regsub_match(repl, str, match);
6539 if (need_backref_str < 0) {
6540 need_backref_str = val != repl;
6541 }
6542 }
6543 else {
6544 val = repl;
6545 }
6546
6547 len = beg0 - offset; /* copy pre-match substr */
6548 if (len) {
6549 rb_enc_str_buf_cat(dest, cp, len, str_enc);
6550 }
6551
6552 rb_str_buf_append(dest, val);
6553
6554 last = offset;
6555 offset = end0;
6556 if (beg0 == end0) {
6557 /*
6558 * Always consume at least one character of the input string
6559 * in order to prevent infinite loops.
6560 */
6561 if (RSTRING_LEN(str) <= end0) break;
6562 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0, RSTRING_END(str), str_enc);
6563 rb_enc_str_buf_cat(dest, RSTRING_PTR(str)+end0, len, str_enc);
6564 offset = end0 + len;
6565 }
6566 cp = RSTRING_PTR(str) + offset;
6567 if (offset > RSTRING_LEN(str)) break;
6568
6569 // In FAST_MAP and STR mode the backref can't escape so we can re-use the MatchData safely.
6570 if (mode != FAST_MAP && mode != STR) {
6571 match = Qnil;
6572 }
6573 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6574
6575 RB_GC_GUARD(match);
6576 } while (beg >= 0);
6577
6578 if (RSTRING_LEN(str) > offset) {
6579 rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
6580 }
6581 rb_pat_search0(pat, str, last, 1, &match);
6582 if (bang) {
6583 str_shared_replace(str, dest);
6584 }
6585 else {
6586 str = dest;
6587 }
6588
6589 return str;
6590}
6591
6592
6593/*
6594 * call-seq:
6595 * gsub!(pattern, replacement) -> self or nil
6596 * gsub!(pattern) {|match| ... } -> self or nil
6597 * gsub!(pattern) -> an_enumerator
6598 *
6599 * Like String#gsub, except that:
6600 *
6601 * - Performs substitutions in +self+ (not in a copy of +self+).
6602 * - Returns +self+ if any substitutions were performed, +nil+ otherwise.
6603 *
6604 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6605 */
6606
6607static VALUE
6608rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
6609{
6610 str_modifiable(str);
6611 return str_gsub(argc, argv, str, 1);
6612}
6613
6614
6615/*
6616 * call-seq:
6617 * gsub(pattern, replacement) -> new_string
6618 * gsub(pattern) {|match| ... } -> new_string
6619 * gsub(pattern) -> enumerator
6620 *
6621 * Returns a copy of +self+ with zero or more substrings replaced.
6622 *
6623 * Argument +pattern+ may be a string or a Regexp;
6624 * argument +replacement+ may be a string or a Hash.
6625 * Varying types for the argument values makes this method very versatile.
6626 *
6627 * Below are some simple examples;
6628 * for many more examples, see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
6629 *
6630 * With arguments +pattern+ and string +replacement+ given,
6631 * replaces each matching substring with the given +replacement+ string:
6632 *
6633 * s = 'abracadabra'
6634 * s.gsub('ab', 'AB') # => "ABracadABra"
6635 * s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
6636 *
6637 * With arguments +pattern+ and hash +replacement+ given,
6638 * replaces each matching substring with a value from the given +replacement+ hash,
6639 * or removes it:
6640 *
6641 * h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
6642 * s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
6643 * s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
6644 *
6645 * With argument +pattern+ and a block given,
6646 * calls the block with each matching substring;
6647 * replaces that substring with the block's return value:
6648 *
6649 * s.gsub(/[a-d]/) {|substring| substring.upcase }
6650 * # => "ABrACADABrA"
6651 *
6652 * With argument +pattern+ and no block given,
6653 * returns a new Enumerator.
6654 *
6655 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
6656 */
6657
6658static VALUE
6659rb_str_gsub(int argc, VALUE *argv, VALUE str)
6660{
6661 return str_gsub(argc, argv, str, 0);
6662}
6663
6664
6665/*
6666 * call-seq:
6667 * replace(other_string) -> self
6668 *
6669 * Replaces the contents of +self+ with the contents of +other_string+;
6670 * returns +self+:
6671 *
6672 * s = 'foo' # => "foo"
6673 * s.replace('bar') # => "bar"
6674 *
6675 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6676 */
6677
6678VALUE
6680{
6681 str_modifiable(str);
6682 if (str == str2) return str;
6683
6684 StringValue(str2);
6685 str_discard(str);
6686 return str_replace(str, str2);
6687}
6688
6689/*
6690 * call-seq:
6691 * clear -> self
6692 *
6693 * Removes the contents of +self+:
6694 *
6695 * s = 'foo'
6696 * s.clear # => ""
6697 * s # => ""
6698 *
6699 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6700 */
6701
6702static VALUE
6703rb_str_clear(VALUE str)
6704{
6705 str_discard(str);
6706 STR_SET_EMBED(str);
6707 STR_SET_LEN(str, 0);
6708 RSTRING_PTR(str)[0] = 0;
6709 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6711 else
6713 return str;
6714}
6715
6716/*
6717 * call-seq:
6718 * chr -> string
6719 *
6720 * :include: doc/string/chr.rdoc
6721 *
6722 */
6723
6724static VALUE
6725rb_str_chr(VALUE str)
6726{
6727 return rb_str_substr(str, 0, 1);
6728}
6729
6730/*
6731 * call-seq:
6732 * getbyte(index) -> integer or nil
6733 *
6734 * :include: doc/string/getbyte.rdoc
6735 *
6736 */
6737VALUE
6738rb_str_getbyte(VALUE str, VALUE index)
6739{
6740 rb_len_t pos = NUM2LEN(index);
6741
6742 if (pos < 0)
6743 pos += RSTRING_LEN(str);
6744 if (pos < 0 || RSTRING_LEN(str) <= pos)
6745 return Qnil;
6746
6747 return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
6748}
6749
6750/*
6751 * call-seq:
6752 * setbyte(index, integer) -> integer
6753 *
6754 * Sets the byte at zero-based offset +index+ to the value of the given +integer+;
6755 * returns +integer+:
6756 *
6757 * s = 'xyzzy'
6758 * s.setbyte(2, 129) # => 129
6759 * s # => "xy\x81zy"
6760 *
6761 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6762 */
6763VALUE
6764rb_str_setbyte(VALUE str, VALUE index, VALUE value)
6765{
6766 rb_len_t pos = NUM2LEN(index);
6767 char *ptr, *head, *left = 0;
6768 rb_encoding *enc;
6769 int cr = ENC_CODERANGE_UNKNOWN, width, nlen;
6770
6771 VALUE v = rb_to_int(value);
6772 VALUE w = rb_int_and(v, INT2FIX(0xff));
6773 char byte = (char)(NUM2INT(w) & 0xFF);
6774
6775 rb_len_t len = RSTRING_LEN(str);
6776 if (pos < -len || len <= pos)
6777 rb_raise(rb_eIndexError, "index %"PRIdLEN" out of string", pos);
6778 if (pos < 0)
6779 pos += len;
6780
6781 if (!str_independent(str))
6782 str_make_independent(str);
6783 enc = STR_ENC_GET(str);
6784 head = RSTRING_PTR(str);
6785 ptr = &head[pos];
6786 if (!STR_EMBED_P(str)) {
6787 cr = ENC_CODERANGE(str);
6788 switch (cr) {
6789 case ENC_CODERANGE_7BIT:
6790 left = ptr;
6791 *ptr = byte;
6792 if (ISASCII(byte)) goto end;
6793 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6794 if (!MBCLEN_CHARFOUND_P(nlen))
6796 else
6798 goto end;
6800 left = rb_enc_left_char_head(head, ptr, head+len, enc);
6801 width = rb_enc_precise_mbclen(left, head+len, enc);
6802 *ptr = byte;
6803 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6804 if (!MBCLEN_CHARFOUND_P(nlen))
6806 else if (MBCLEN_CHARFOUND_LEN(nlen) != width || ISASCII(byte))
6808 goto end;
6809 }
6810 }
6812 *ptr = byte;
6813
6814 end:
6815 return value;
6816}
6817
6818static inline bool
6819str_bit_offset_out_of_range(rb_len_t byte_len, uint64_t bit_offset)
6820{
6821 /* Compare byte indexes to avoid overflowing byte_len * CHAR_BIT. */
6822 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6823}
6824
6825/*
6826 * Keep both the full bit offset and its rb_len_t representation. Most calls
6827 * use a Fixnum-sized offset and can stay on the rb_len_t fast path; only large
6828 * Bignum offsets need the uint64_t path below. This matters on platforms where
6829 * rb_len_t is narrower than the address space, such as 32-bit and LLP64.
6830 */
6832 uint64_t value;
6833 rb_len_t index_value;
6834 bool fits_index;
6835};
6836
6837static inline struct str_bit_offset
6838str_bit_offset_from_index(VALUE index)
6839{
6840 VALUE integer = rb_to_int(index);
6841 struct str_bit_offset offset;
6842
6843 /*
6844 * FIXNUM_P only decides whether the common rb_len_t path is immediately
6845 * usable. This covers practically all offsets on LP64 platforms; Bignum
6846 * offsets are still accepted below when they fit in uint64_t, mainly for
6847 * platforms with 32-bit rb_len_t where large strings can have Bignum bit
6848 * offsets.
6849 */
6850 if (FIXNUM_P(integer)) {
6851 offset.index_value = FIX2LONG(integer);
6852 if (offset.index_value < 0) {
6853 rb_raise(rb_eIndexError, "bit index out of range");
6854 }
6855 offset.value = (uint64_t)offset.index_value;
6856 offset.fits_index = true;
6857 return offset;
6858 }
6859
6860 RUBY_ASSERT(RB_TYPE_P(integer, T_BIGNUM));
6861 if (rb_int_negative_p(integer)) {
6862 rb_raise(rb_eIndexError, "bit index out of range");
6863 }
6864 if (rb_cmpint(rb_int_cmp(integer, ULL2NUM(UINT64_MAX)), integer, ULL2NUM(UINT64_MAX)) > 0) {
6865 rb_raise(rb_eArgError, "bit index out of representable range");
6866 }
6867
6868 offset.value = (uint64_t)NUM2ULL(integer);
6869 if (offset.value <= (uint64_t)RB_LEN_MAX) {
6870 offset.index_value = (rb_len_t)offset.value;
6871 offset.fits_index = true;
6872 }
6873 else {
6874 offset.index_value = 0;
6875 offset.fits_index = false;
6876 }
6877 return offset;
6878}
6879
6880/*
6881 * Bit lengths share the offset's representable range.
6882 * A negative length is an ArgumentError rather than an IndexError.
6883 */
6884static uint64_t
6885str_bit_length_from_index(VALUE index)
6886{
6887 VALUE integer = rb_to_int(index);
6888
6889 if (FIXNUM_P(integer)) {
6890 rb_len_t value = FIX2LONG(integer);
6891 if (value < 0) {
6892 rb_raise(rb_eArgError, "negative bit length");
6893 }
6894 return (uint64_t)value;
6895 }
6896
6897 RUBY_ASSERT(RB_TYPE_P(integer, T_BIGNUM));
6898 if (rb_int_negative_p(integer)) {
6899 rb_raise(rb_eArgError, "negative bit length");
6900 }
6901 if (rb_cmpint(rb_int_cmp(integer, ULL2NUM(UINT64_MAX)), integer, ULL2NUM(UINT64_MAX)) > 0) {
6902 rb_raise(rb_eArgError, "bit length out of representable range");
6903 }
6904 return (uint64_t)NUM2ULL(integer);
6905}
6906
6907static inline uint64_t
6908str_bit_size(rb_len_t byte_len)
6909{
6910 /*
6911 * byte_len * CHAR_BIT overflows uint64_t only for byte_len >= 2**61 which cannot
6912 * be allocated. Saturate so that unreachable cases cannot wrap.
6913 */
6914 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT) return UINT64_MAX;
6915 return (uint64_t)byte_len * CHAR_BIT;
6916}
6917
6919 uint64_t beg;
6920 uint64_t end_exclusive; /* meaningful only when end_open is false */
6921 bool end_open; /* a nil end: the region runs to the end of self */
6922};
6923
6924/*
6925 * Coerce a bit Range's endpoints to bit offsets. This may run arbitrary Ruby
6926 * (Integer#to_int on the endpoints), so it does NOT read the string's length:
6927 * The caller must resolve the length only after this returns, otherwise
6928 * to_int that reallocates self would leave a stale size.
6929 */
6930static void
6931str_bit_range_to_offsets(VALUE range, struct str_bit_range *out)
6932{
6933 VALUE beg_v, end_v;
6934 int excl;
6935
6936 /*
6937 * We don't use rb_range_beg_len: it counts negative endpoints from the end,
6938 * which is an IndexError for bit positions, and it is limited to long instead
6939 * of uint64_t.
6940 */
6941 rb_range_values(range, &beg_v, &end_v, &excl);
6942
6943 out->beg = NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6944 if (NIL_P(end_v)) {
6945 out->end_open = true;
6946 out->end_exclusive = 0;
6947 }
6948 else {
6949 uint64_t end = str_bit_offset_from_index(end_v).value;
6950 out->end_open = false;
6951 /*
6952 * The saturation loses one position only for an inclusive end of
6953 * 2**64-1, which lies beyond any real string either way.
6954 */
6955 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6956 }
6957}
6958
6959/*
6960 * Turn a coerced Range into (beg, len) against the now-current total bit size.
6961 * The length is deliberately not clamped to the bits available, so a reading
6962 * caller can clamp while a writing caller detects the overrun and raises.
6963 */
6964static bool
6965str_bit_range_resolve(const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6966{
6967 uint64_t beg = range->beg;
6968 if (beg > total_bits) return false;
6969
6970 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6971 if (end_exclusive < beg) end_exclusive = beg;
6972
6973 *begp = beg;
6974 *lenp = end_exclusive - beg;
6975 return true;
6976}
6977
6978static bool
6979str_lsb_first_from_opts(VALUE opts)
6980{
6981 static ID keywords[1];
6982 VALUE vlsb_first;
6983
6984 if (!keywords[0]) {
6985 keywords[0] = rb_intern_const("lsb_first");
6986 }
6987
6988 rb_get_kwargs(opts, keywords, 0, 1, &vlsb_first);
6989 if (vlsb_first == Qundef || vlsb_first == Qtrue) {
6990 return true;
6991 }
6992 if (vlsb_first == Qfalse) {
6993 return false;
6994 }
6995 rb_raise(rb_eArgError, "lsb_first must be true or false");
6996 UNREACHABLE_RETURN(false);
6997}
6998
6999static bool
7000str_lsb_first(int argc, VALUE *argv, VALUE *index)
7001{
7002 VALUE opts;
7003
7004 rb_scan_args(argc, argv, "1:", index, &opts);
7005 return str_lsb_first_from_opts(opts);
7006}
7007
7008static inline uint64_t
7009str_logical_to_physical_bit64(uint64_t logical, bool lsb_first)
7010{
7011 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
7012}
7013
7014static inline rb_len_t
7015str_logical_to_physical_bit(rb_len_t logical, bool lsb_first)
7016{
7017 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
7018}
7019
7021 rb_len_t byte_index;
7022 unsigned int bit_offset;
7023};
7024
7025static inline struct str_bit_location
7026str_bit_location_from_offset(uint64_t logical, bool lsb_first)
7027{
7028 /*
7029 * When rb_len_t is 32-bit, a bit offset for a large string can be a Bignum
7030 * while the byte index still fits in rb_len_t, which is RSTRING_LEN's type.
7031 */
7032 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7033 struct str_bit_location location;
7034 location.byte_index = (rb_len_t)(physical / CHAR_BIT);
7035 location.bit_offset = (unsigned int)(physical % CHAR_BIT);
7036 return location;
7037}
7038
7039static inline int
7040str_get_bit(const char *ptr, rb_len_t bit_index)
7041{
7042 return (((unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7043}
7044
7045static inline int
7046str_get_bit_location(const char *ptr, struct str_bit_location location)
7047{
7048 return (((unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7049}
7050
7051static int
7052str_bit_get(int argc, VALUE *argv, VALUE str)
7053{
7054 VALUE index;
7055 bool lsb_first = str_lsb_first(argc, argv, &index);
7056 struct str_bit_offset offset = str_bit_offset_from_index(index);
7057
7058 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7059 return -1;
7060 }
7061
7062 if (offset.fits_index) {
7063 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.index_value, lsb_first));
7064 }
7065 else {
7066 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7067 }
7068}
7069
7070/*
7071 * call-seq:
7072 * bit_get(offset, lsb_first: true) -> 0, 1, or nil
7073 *
7074 * :include: doc/string/bit_get.rdoc
7075 *
7076 */
7077static VALUE
7078rb_str_bit_get(int argc, VALUE *argv, VALUE str)
7079{
7080 int bit = str_bit_get(argc, argv, str);
7081 return bit < 0 ? Qnil : INT2FIX(bit);
7082}
7083
7084/*
7085 * call-seq:
7086 * bit_set?(offset, lsb_first: true) -> true, false, or nil
7087 *
7088 * :include: doc/string/bit_set_p.rdoc
7089 *
7090 */
7091static VALUE
7092rb_str_bit_set_p(int argc, VALUE *argv, VALUE str)
7093{
7094 int bit = str_bit_get(argc, argv, str);
7095 return bit < 0 ? Qnil : RBOOL(bit);
7096}
7097
7098enum str_bit_mutation {
7099 STR_BIT_SET,
7100 STR_BIT_CLEAR,
7101 STR_BIT_FLIP
7102};
7103
7104/*
7105 * Mask for the logical in-byte positions lo..hi (0 <= lo <= hi <= 7) of one
7106 * byte. A contiguous logical run stays contiguous within a byte under both
7107 * numbering conventions; MSB-first only mirrors it.
7108 */
7109static inline unsigned char
7110str_bit_region_byte_mask(unsigned int lo, unsigned int hi, bool lsb_first)
7111{
7112 if (lsb_first) {
7113 return (unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7114 }
7115 else {
7116 return (unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7117 }
7118}
7119
7120static inline void
7121str_apply_bit_mask(unsigned char *byte, unsigned char mask, enum str_bit_mutation mutation)
7122{
7123 switch (mutation) {
7124 case STR_BIT_SET:
7125 *byte |= mask;
7126 break;
7127 case STR_BIT_CLEAR:
7128 *byte &= (unsigned char)~mask;
7129 break;
7130 case STR_BIT_FLIP:
7131 *byte ^= mask;
7132 break;
7133 }
7134}
7135
7136/* The caller has bounds-checked [beg, beg+len) and called rb_str_modify. */
7137static void
7138str_mutate_bit_region(unsigned char *ptr, uint64_t beg, uint64_t len, bool lsb_first, enum str_bit_mutation mutation)
7139{
7140 uint64_t first_bit = beg;
7141 uint64_t last_bit = beg + len - 1;
7142 rb_len_t first_byte = (rb_len_t)(first_bit / CHAR_BIT);
7143 rb_len_t last_byte = (rb_len_t)(last_bit / CHAR_BIT);
7144 unsigned int first_off = (unsigned int)(first_bit % CHAR_BIT);
7145 unsigned int last_off = (unsigned int)(last_bit % CHAR_BIT);
7146
7147 if (first_byte == last_byte) {
7148 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7149 return;
7150 }
7151
7152 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7153 rb_len_t middle_len = last_byte - first_byte - 1;
7154 if (middle_len > 0) {
7155 unsigned char *middle = ptr + first_byte + 1;
7156 switch (mutation) {
7157 case STR_BIT_SET:
7158 memset(middle, 0xFF, middle_len);
7159 break;
7160 case STR_BIT_CLEAR:
7161 memset(middle, 0, middle_len);
7162 break;
7163 case STR_BIT_FLIP:
7164 /*
7165 * Byte loop on purpose: the compiler auto-vectorizes it (verified on gcc 13.3
7166 * and clang 18.1 with x86_64), and being read-modify-write, the flip is memory-bound,
7167 * so a manual word-at-a-time XOR loop was measured to be no faster.
7168 */
7169 for (rb_len_t i = 0; i < middle_len; i++) {
7170 middle[i] ^= 0xFF;
7171 }
7172 break;
7173 }
7174 }
7175 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7176}
7177
7178static VALUE
7179str_mutate_single_bit(VALUE str, VALUE index, bool lsb_first, enum str_bit_mutation mutation)
7180{
7181 struct str_bit_offset offset = str_bit_offset_from_index(index);
7182 struct str_bit_location location;
7183 rb_len_t bit_index;
7184 unsigned char *ptr;
7185 unsigned char mask;
7186
7187 rb_check_frozen(str);
7188
7189 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7190 rb_raise(rb_eIndexError, "bit index out of range");
7191 }
7192
7193 rb_str_modify(str);
7194 ptr = (unsigned char *)RSTRING_PTR(str);
7195 if (offset.fits_index) {
7196 bit_index = str_logical_to_physical_bit(offset.index_value, lsb_first);
7197 mask = (unsigned char)(1u << (bit_index % CHAR_BIT));
7198 location.byte_index = bit_index / CHAR_BIT;
7199 }
7200 else {
7201 location = str_bit_location_from_offset(offset.value, lsb_first);
7202 mask = (unsigned char)(1u << location.bit_offset);
7203 }
7204
7205 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7206 return str;
7207}
7208
7209static VALUE
7210str_mutate_bit(int argc, VALUE *argv, VALUE str, enum str_bit_mutation mutation)
7211{
7212 VALUE target, length_v, opts;
7213 uint64_t beg = 0, len = 0;
7214
7215 /* Count positional arguments so that an explicit nil is not mistaken for an omitted one. */
7216 int nargs = rb_scan_args(argc, argv, "11:", &target, &length_v, &opts);
7217 bool lsb_first = str_lsb_first_from_opts(opts);
7218
7219 bool is_range = rb_obj_is_kind_of(target, rb_cRange);
7220 if (nargs == 1 && !is_range) {
7221 return str_mutate_single_bit(str, target, lsb_first, mutation);
7222 }
7223
7224 struct str_bit_range range = {0};
7225 struct str_bit_offset offset;
7226 if (is_range) {
7227 if (nargs == 2) {
7228 rb_raise(rb_eArgError, "bit length not allowed with a Range");
7229 }
7230 str_bit_range_to_offsets(target, &range);
7231 }
7232 else {
7233 offset = str_bit_offset_from_index(target);
7234 len = str_bit_length_from_index(length_v);
7235 }
7236
7237 /* Even a zero-length write requires a mutable receiver. */
7238 rb_check_frozen(str);
7239
7240 /*
7241 * A region that begins past the end is out of range even when it is
7242 * empty, and one that runs past the end is not allowed to silently
7243 * shrink: both are errors for a mutation, unlike the clamping reads.
7244 * An empty region whose start is within 0..bitsize writes nothing.
7245 */
7246 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7247 if (is_range) {
7248 if (!str_bit_range_resolve(&range, total_bits, &beg, &len) || len > total_bits - beg) {
7249 rb_raise(rb_eIndexError, "bit range out of range");
7250 }
7251 }
7252 else {
7253 beg = offset.value;
7254 if (beg > total_bits || len > total_bits - beg) {
7255 rb_raise(rb_eIndexError, "bit range out of range");
7256 }
7257 }
7258
7259 if (len == 0) return str;
7260
7261 rb_str_modify(str);
7262 str_mutate_bit_region((unsigned char *)RSTRING_PTR(str), beg, len, lsb_first, mutation);
7263 return str;
7264}
7265
7266/*
7267 * call-seq:
7268 * bit_set(offset, lsb_first: true) -> self
7269 * bit_set(offset, length, lsb_first: true) -> self
7270 * bit_set(range, lsb_first: true) -> self
7271 *
7272 * :include: doc/string/bit_set.rdoc
7273 *
7274 */
7275static VALUE
7276rb_str_bit_set(int argc, VALUE *argv, VALUE str)
7277{
7278 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7279}
7280
7281/*
7282 * call-seq:
7283 * bit_clear(offset, lsb_first: true) -> self
7284 * bit_clear(offset, length, lsb_first: true) -> self
7285 * bit_clear(range, lsb_first: true) -> self
7286 *
7287 * :include: doc/string/bit_clear.rdoc
7288 *
7289 */
7290static VALUE
7291rb_str_bit_clear(int argc, VALUE *argv, VALUE str)
7292{
7293 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7294}
7295
7296/*
7297 * call-seq:
7298 * bit_flip(offset, lsb_first: true) -> self
7299 * bit_flip(offset, length, lsb_first: true) -> self
7300 * bit_flip(range, lsb_first: true) -> self
7301 *
7302 * :include: doc/string/bit_flip.rdoc
7303 *
7304 */
7305static VALUE
7306rb_str_bit_flip(int argc, VALUE *argv, VALUE str)
7307{
7308 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7309}
7310
7311static uint64_t
7312str_count_bits(const unsigned char *ptr, rb_len_t len)
7313{
7314 uint64_t count = 0;
7315 rb_len_t off = 0;
7316 rb_len_t unrolled_end = len & ~31L;
7317 rb_len_t aligned_end = len & ~7L;
7318
7319 // 32 bytes (256 bits) at a time
7320 for (; off < unrolled_end; off += 32) {
7321 uint64_t w0, w1, w2, w3;
7322 memcpy(&w0, ptr + off, 8);
7323 memcpy(&w1, ptr + off + 8, 8);
7324 memcpy(&w2, ptr + off + 16, 8);
7325 memcpy(&w3, ptr + off + 24, 8);
7326 count += rb_popcount64(w0);
7327 count += rb_popcount64(w1);
7328 count += rb_popcount64(w2);
7329 count += rb_popcount64(w3);
7330 }
7331
7332 // 8 bytes (64 bits) at a time
7333 for (; off < aligned_end; off += 8) {
7334 uint64_t word;
7335 memcpy(&word, ptr + off, 8);
7336 count += rb_popcount64(word);
7337 }
7338
7339 // remaining bytes
7340 if (off < len) {
7341 uint64_t word = 0;
7342 int shift = 0;
7343 for (; off < len; off++, shift += CHAR_BIT) {
7344 word |= (uint64_t)ptr[off] << shift;
7345 }
7346 count += rb_popcount64(word);
7347 }
7348
7349 return count;
7350}
7351
7352static uint64_t
7353str_count_bits_region(const unsigned char *ptr, uint64_t beg, uint64_t len, bool lsb_first)
7354{
7355 uint64_t first_bit = beg;
7356 uint64_t last_bit = beg + len - 1;
7357 rb_len_t first_byte = (rb_len_t)(first_bit / CHAR_BIT);
7358 rb_len_t last_byte = (rb_len_t)(last_bit / CHAR_BIT);
7359 unsigned int first_off = (unsigned int)(first_bit % CHAR_BIT);
7360 unsigned int last_off = (unsigned int)(last_bit % CHAR_BIT);
7361
7362 if (first_byte == last_byte) {
7363 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7364 }
7365
7366 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7367 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7368 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7369 return count;
7370}
7371
7372/*
7373 * call-seq:
7374 * bit_count -> integer
7375 * bit_count(offset, length, lsb_first: true) -> integer
7376 * bit_count(range, lsb_first: true) -> integer
7377 *
7378 * :include: doc/string/bit_count.rdoc
7379 *
7380 */
7381static VALUE
7382rb_str_bit_count(int argc, VALUE *argv, VALUE str)
7383{
7384 VALUE v0, v1, opts;
7385 uint64_t beg = 0, len = 0;
7386
7387 /* Count positional arguments so that an explicit nil is not mistaken for an omitted one. */
7388 int nargs = rb_scan_args(argc, argv, "02:", &v0, &v1, &opts);
7389 /*
7390 * A whole-string popcount is independent of bit numbering.
7391 * no-(offset|range)-argument form only validates lsb_first.
7392 */
7393 bool lsb_first = str_lsb_first_from_opts(opts);
7394
7395 if (nargs == 0) {
7396 return ULL2NUM(str_count_bits((const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7397 }
7398
7399 bool is_range = rb_obj_is_kind_of(v0, rb_cRange);
7400 struct str_bit_range range = {0};
7401 if (is_range) {
7402 if (nargs == 2) {
7403 rb_raise(rb_eArgError, "bit length not allowed with a Range");
7404 }
7405 str_bit_range_to_offsets(v0, &range);
7406 }
7407 else if (nargs == 1) {
7408 rb_raise(rb_eArgError, "no bit length given");
7409 }
7410 else {
7411 beg = str_bit_offset_from_index(v0).value;
7412 len = str_bit_length_from_index(v1);
7413 }
7414
7415 const unsigned char *ptr = (const unsigned char *)RSTRING_PTR(str);
7416 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7417 if (is_range) {
7418 if (!str_bit_range_resolve(&range, total_bits, &beg, &len)) {
7419 return INT2FIX(0);
7420 }
7421 }
7422 else if (beg >= total_bits) {
7423 return INT2FIX(0);
7424 }
7425
7426 /* Reads clamp: only the part of the region that exists is counted. */
7427 if (len > total_bits - beg) len = total_bits - beg;
7428 if (len == 0) return INT2FIX(0);
7429 return ULL2NUM(str_count_bits_region(ptr, beg, len, lsb_first));
7430}
7431
7432static void
7433str_check_bitwise_length(VALUE str, VALUE other)
7434{
7435 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7436 rb_raise(rb_eArgError, "operands must have the same length (%"PRIdLEN" vs %"PRIdLEN")",
7437 RSTRING_LEN(str), RSTRING_LEN(other));
7438 }
7439}
7440
7441static VALUE
7442str_bitwise_result(VALUE str)
7443{
7444 rb_len_t len = RSTRING_LEN(str);
7445 VALUE result = rb_str_buf_new(len);
7446 rb_str_resize(result, len);
7447 rb_enc_associate(result, rb_ascii8bit_encoding());
7448 ENC_CODERANGE_CLEAR(result);
7449 return result;
7450}
7451
7452#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7453 static void \
7454 name(unsigned char *dst, const unsigned char *src, rb_len_t len) \
7455 { \
7456 rb_len_t off = 0; \
7457 rb_len_t unrolled_end = len & ~31L; \
7458 rb_len_t aligned_end = len & ~7L; \
7459 for (; off < unrolled_end; off += 32) { \
7460 uint64_t s0, s1, s2, s3; \
7461 memcpy(&s0, src + off, 8); \
7462 memcpy(&s1, src + off + 8, 8); \
7463 memcpy(&s2, src + off + 16, 8); \
7464 memcpy(&s3, src + off + 24, 8); \
7465 s0 = (expr_word(s0)); \
7466 s1 = (expr_word(s1)); \
7467 s2 = (expr_word(s2)); \
7468 s3 = (expr_word(s3)); \
7469 memcpy(dst + off, &s0, 8); \
7470 memcpy(dst + off + 8, &s1, 8); \
7471 memcpy(dst + off + 16, &s2, 8); \
7472 memcpy(dst + off + 24, &s3, 8); \
7473 } \
7474 for (; off < aligned_end; off += 8) { \
7475 uint64_t word; \
7476 memcpy(&word, src + off, 8); \
7477 word = (expr_word(word)); \
7478 memcpy(dst + off, &word, 8); \
7479 } \
7480 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7481 }
7482
7483#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7484 static void \
7485 name(unsigned char *dst, const unsigned char *lhs, \
7486 const unsigned char *rhs, rb_len_t len) \
7487 { \
7488 rb_len_t off = 0; \
7489 rb_len_t unrolled_end = len & ~31L; \
7490 rb_len_t aligned_end = len & ~7L; \
7491 for (; off < unrolled_end; off += 32) { \
7492 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7493 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7494 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7495 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7496 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7497 l0 = expr_word(l0, r0); \
7498 l1 = expr_word(l1, r1); \
7499 l2 = expr_word(l2, r2); \
7500 l3 = expr_word(l3, r3); \
7501 memcpy(dst + off, &l0, 8); \
7502 memcpy(dst + off + 8, &l1, 8); \
7503 memcpy(dst + off + 16, &l2, 8); \
7504 memcpy(dst + off + 24, &l3, 8); \
7505 } \
7506 for (; off < aligned_end; off += 8) { \
7507 uint64_t lhs_word, rhs_word; \
7508 memcpy(&lhs_word, lhs + off, 8); \
7509 memcpy(&rhs_word, rhs + off, 8); \
7510 lhs_word = expr_word(lhs_word, rhs_word); \
7511 memcpy(dst + off, &lhs_word, 8); \
7512 } \
7513 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7514 }
7515
7516#define STR_BITWISE_NOT_WORD(x) (~(x))
7517#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7518#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7519#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7520#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7521#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7522#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7523#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7524
7525STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7526STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7527STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7528STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7529
7530/*
7531 * call-seq:
7532 * bitwise_not -> string
7533 *
7534 * :include: doc/string/bitwise_not.rdoc
7535 *
7536 */
7537static VALUE
7538rb_str_bitwise_not(VALUE str)
7539{
7540 rb_len_t len = RSTRING_LEN(str);
7541 VALUE result = str_bitwise_result(str);
7542 str_bitwise_not((unsigned char *)RSTRING_PTR(result),
7543 (const unsigned char *)RSTRING_PTR(str), len);
7544 return result;
7545}
7546
7547/*
7548 * call-seq:
7549 * bitwise_not! -> self
7550 *
7551 * :include: doc/string/bitwise_not_bang.rdoc
7552 *
7553 */
7554static VALUE
7555rb_str_bitwise_not_bang(VALUE str)
7556{
7557 rb_len_t len;
7558 unsigned char *ptr;
7559
7560 rb_str_modify(str);
7561 len = RSTRING_LEN(str);
7562 ptr = (unsigned char *)RSTRING_PTR(str);
7563 str_bitwise_not(ptr, ptr, len);
7564 return str;
7565}
7566
7567#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7568 static VALUE \
7569 rb_str_bitwise_##name(VALUE str, VALUE other) \
7570 { \
7571 rb_len_t len; \
7572 VALUE result; \
7573 StringValue(other); \
7574 str_check_bitwise_length(str, other); \
7575 len = RSTRING_LEN(str); \
7576 result = str_bitwise_result(str); \
7577 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7578 (const unsigned char *)RSTRING_PTR(str), \
7579 (const unsigned char *)RSTRING_PTR(other), len); \
7580 return result; \
7581 } \
7582 static VALUE \
7583 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7584 { \
7585 rb_len_t len; \
7586 unsigned char *ptr; \
7587 StringValue(other); \
7588 str_check_bitwise_length(str, other); \
7589 rb_str_modify(str); \
7590 len = RSTRING_LEN(str); \
7591 ptr = (unsigned char *)RSTRING_PTR(str); \
7592 str_bitwise_##name(ptr, ptr, \
7593 (const unsigned char *)RSTRING_PTR(other), len); \
7594 return str; \
7595 }
7596
7597STR_DEFINE_BINARY_BITWISE_METHOD(and)
7598STR_DEFINE_BINARY_BITWISE_METHOD(or)
7599STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7600
7601static VALUE
7602str_byte_substr(VALUE str, rb_len_t beg, rb_len_t len, int empty)
7603{
7604 rb_len_t n = RSTRING_LEN(str);
7605
7606 if (beg > n || len < 0) return Qnil;
7607 if (beg < 0) {
7608 beg += n;
7609 if (beg < 0) return Qnil;
7610 }
7611 if (len > n - beg)
7612 len = n - beg;
7613 if (len <= 0) {
7614 if (!empty) return Qnil;
7615 len = 0;
7616 }
7617
7618 VALUE str2 = str_subseq(str, beg, len);
7619
7620 str_enc_copy_direct(str2, str);
7621
7622 if (RSTRING_LEN(str2) == 0) {
7623 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7625 else
7627 }
7628 else {
7629 switch (ENC_CODERANGE(str)) {
7630 case ENC_CODERANGE_7BIT:
7632 break;
7633 default:
7635 break;
7636 }
7637 }
7638
7639 return str2;
7640}
7641
7642VALUE
7643rb_str_byte_substr(VALUE str, VALUE beg, VALUE len)
7644{
7645 return str_byte_substr(str, NUM2LEN(beg), NUM2LEN(len), TRUE);
7646}
7647
7648static VALUE
7649str_byte_aref(VALUE str, VALUE indx)
7650{
7651 rb_len_t idx;
7652 if (FIXNUM_P(indx)) {
7653 idx = FIX2LONG(indx);
7654 }
7655 else {
7656 /* check if indx is Range */
7657 rb_len_t beg, len = RSTRING_LEN(str);
7658
7659 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
7660 case Qfalse:
7661 break;
7662 case Qnil:
7663 return Qnil;
7664 default:
7665 return str_byte_substr(str, beg, len, TRUE);
7666 }
7667
7668 idx = NUM2LEN(indx);
7669 }
7670 return str_byte_substr(str, idx, 1, FALSE);
7671}
7672
7673/*
7674 * call-seq:
7675 * byteslice(offset, length = 1) -> string or nil
7676 * byteslice(range) -> string or nil
7677 *
7678 * :include: doc/string/byteslice.rdoc
7679 */
7680
7681static VALUE
7682rb_str_byteslice(int argc, VALUE *argv, VALUE str)
7683{
7684 if (argc == 2) {
7685 rb_len_t beg = NUM2LEN(argv[0]);
7686 rb_len_t len = NUM2LEN(argv[1]);
7687 return str_byte_substr(str, beg, len, TRUE);
7688 }
7689 rb_check_arity(argc, 1, 2);
7690 return str_byte_aref(str, argv[0]);
7691}
7692
7693static void
7694str_check_beg_len(VALUE str, rb_len_t *beg, rb_len_t *len)
7695{
7696 rb_len_t end, slen = RSTRING_LEN(str);
7697
7698 if (*len < 0) rb_raise(rb_eIndexError, "negative length %"PRIdLEN, *len);
7699 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7700 rb_raise(rb_eIndexError, "index %"PRIdLEN" out of string", *beg);
7701 }
7702 if (*beg < 0) {
7703 *beg += slen;
7704 }
7705 RUBY_ASSERT(*beg >= 0);
7706 RUBY_ASSERT(*beg <= slen);
7707
7708 if (*len > slen - *beg) {
7709 *len = slen - *beg;
7710 }
7711 end = *beg + *len;
7712 str_ensure_byte_pos(str, *beg);
7713 str_ensure_byte_pos(str, end);
7714}
7715
7716/*
7717 * call-seq:
7718 * bytesplice(offset, length, str) -> self
7719 * bytesplice(offset, length, str, str_offset, str_length) -> self
7720 * bytesplice(range, str) -> self
7721 * bytesplice(range, str, str_range) -> self
7722 *
7723 * :include: doc/string/bytesplice.rdoc
7724 */
7725
7726static VALUE
7727rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
7728{
7729 rb_len_t beg, len, vbeg, vlen;
7730 VALUE val;
7731 int cr;
7732
7733 rb_check_arity(argc, 2, 5);
7734 if (!(argc == 2 || argc == 3 || argc == 5)) {
7735 rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7736 }
7737 if (argc == 2 || (argc == 3 && !RB_INTEGER_TYPE_P(argv[0]))) {
7738 if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
7739 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7740 rb_builtin_class_name(argv[0]));
7741 }
7742 val = argv[1];
7743 StringValue(val);
7744 if (argc == 2) {
7745 /* bytesplice(range, str) */
7746 vbeg = 0;
7747 vlen = RSTRING_LEN(val);
7748 }
7749 else {
7750 /* bytesplice(range, str, str_range) */
7751 if (!rb_range_beg_len(argv[2], &vbeg, &vlen, RSTRING_LEN(val), 2)) {
7752 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7753 rb_builtin_class_name(argv[2]));
7754 }
7755 }
7756 }
7757 else {
7758 beg = NUM2LEN(argv[0]);
7759 len = NUM2LEN(argv[1]);
7760 val = argv[2];
7761 StringValue(val);
7762 if (argc == 3) {
7763 /* bytesplice(index, length, str) */
7764 vbeg = 0;
7765 vlen = RSTRING_LEN(val);
7766 }
7767 else {
7768 /* bytesplice(index, length, str, str_index, str_length) */
7769 vbeg = NUM2LEN(argv[3]);
7770 vlen = NUM2LEN(argv[4]);
7771 }
7772 }
7773 str_check_beg_len(str, &beg, &len);
7774 str_check_beg_len(val, &vbeg, &vlen);
7775 str_modify_keep_cr(str);
7776
7777 if (RB_UNLIKELY(ENCODING_GET_INLINED(str) != ENCODING_GET_INLINED(val))) {
7778 rb_enc_associate(str, rb_enc_check(str, val));
7779 }
7780
7781 rb_str_update_1(str, beg, len, val, vbeg, vlen);
7783 if (cr != ENC_CODERANGE_BROKEN)
7784 ENC_CODERANGE_SET(str, cr);
7785 return str;
7786}
7787
7788/*
7789 * call-seq:
7790 * reverse -> new_string
7791 *
7792 * Returns a new string with the characters from +self+ in reverse order.
7793 *
7794 * 'drawer'.reverse # => "reward"
7795 * 'reviled'.reverse # => "deliver"
7796 * 'stressed'.reverse # => "desserts"
7797 * 'semordnilaps'.reverse # => "spalindromes"
7798 *
7799 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7800 */
7801
7802static VALUE
7803rb_str_reverse(VALUE str)
7804{
7805 rb_encoding *enc;
7806 VALUE rev;
7807 char *s, *e, *p;
7808 int cr;
7809
7810 if (RSTRING_LEN(str) <= 1) return str_duplicate(rb_cString, str);
7811 enc = STR_ENC_GET(str);
7812 rev = rb_str_new(0, RSTRING_LEN(str));
7813 s = RSTRING_PTR(str); e = RSTRING_END(str);
7814 p = RSTRING_END(rev);
7815 cr = ENC_CODERANGE(str);
7816
7817 if (RSTRING_LEN(str) > 1) {
7818 if (single_byte_optimizable(str)) {
7819 while (s < e) {
7820 *--p = *s++;
7821 }
7822 }
7823 else if (cr == ENC_CODERANGE_VALID) {
7824 while (s < e) {
7825 int clen = rb_enc_fast_mbclen(s, e, enc);
7826
7827 p -= clen;
7828 memcpy(p, s, clen);
7829 s += clen;
7830 }
7831 }
7832 else {
7833 cr = rb_enc_asciicompat(enc) ?
7835 while (s < e) {
7836 int clen = rb_enc_mbclen(s, e, enc);
7837
7838 if (clen > 1 || (*s & 0x80)) cr = ENC_CODERANGE_UNKNOWN;
7839 p -= clen;
7840 memcpy(p, s, clen);
7841 s += clen;
7842 }
7843 }
7844 }
7845 STR_SET_LEN(rev, RSTRING_LEN(str));
7846 str_enc_copy_direct(rev, str);
7847 ENC_CODERANGE_SET(rev, cr);
7848
7849 return rev;
7850}
7851
7852
7853/*
7854 * call-seq:
7855 * reverse! -> self
7856 *
7857 * Returns +self+ with its characters reversed:
7858 *
7859 * 'drawer'.reverse! # => "reward"
7860 * 'reviled'.reverse! # => "deliver"
7861 * 'stressed'.reverse! # => "desserts"
7862 * 'semordnilaps'.reverse! # => "spalindromes"
7863 *
7864 * Related: see {Modifying}[rdoc-ref:String@Modifying].
7865 */
7866
7867static VALUE
7868rb_str_reverse_bang(VALUE str)
7869{
7870 if (RSTRING_LEN(str) > 1) {
7871 if (single_byte_optimizable(str)) {
7872 char *s, *e, c;
7873
7874 str_modify_keep_cr(str);
7875 s = RSTRING_PTR(str);
7876 e = RSTRING_END(str) - 1;
7877 while (s < e) {
7878 c = *s;
7879 *s++ = *e;
7880 *e-- = c;
7881 }
7882 }
7883 else {
7884 str_shared_replace(str, rb_str_reverse(str));
7885 }
7886 }
7887 else {
7888 str_modify_keep_cr(str);
7889 }
7890 return str;
7891}
7892
7893
7894/*
7895 * call-seq:
7896 * include?(other_string) -> true or false
7897 *
7898 * Returns whether +self+ contains +other_string+:
7899 *
7900 * s = 'bar'
7901 * s.include?('ba') # => true
7902 * s.include?('ar') # => true
7903 * s.include?('bar') # => true
7904 * s.include?('a') # => true
7905 * s.include?('') # => true
7906 * s.include?('foo') # => false
7907 *
7908 * Related: see {Querying}[rdoc-ref:String@Querying].
7909 */
7910
7911VALUE
7912rb_str_include(VALUE str, VALUE arg)
7913{
7914 rb_len_t i;
7915
7916 StringValue(arg);
7917 i = rb_str_index(str, arg, 0);
7918
7919 return RBOOL(i != -1);
7920}
7921
7922
7923/*
7924 * call-seq:
7925 * to_i(base = 10) -> integer
7926 *
7927 * Returns the result of interpreting leading characters in +self+
7928 * as an integer in the given +base+;
7929 * +base+ must be either +0+ or in range <tt>(2..36)</tt>:
7930 *
7931 * '123456'.to_i # => 123456
7932 * '123def'.to_i(16) # => 1195503
7933 *
7934 * With +base+ zero given, string +object+ may contain leading characters
7935 * to specify the actual base:
7936 *
7937 * '123def'.to_i(0) # => 123
7938 * '0123def'.to_i(0) # => 83
7939 * '0b123def'.to_i(0) # => 1
7940 * '0o123def'.to_i(0) # => 83
7941 * '0d123def'.to_i(0) # => 123
7942 * '0x123def'.to_i(0) # => 1195503
7943 *
7944 * Characters past a leading valid number (in the given +base+) are ignored:
7945 *
7946 * '12.345'.to_i # => 12
7947 * '12345'.to_i(2) # => 1
7948 *
7949 * Returns zero if there is no leading valid number:
7950 *
7951 * 'abcdef'.to_i # => 0
7952 * '2'.to_i(2) # => 0
7953 *
7954 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
7955 */
7956
7957static VALUE
7958rb_str_to_i(int argc, VALUE *argv, VALUE str)
7959{
7960 int base = 10;
7961
7962 if (rb_check_arity(argc, 0, 1) && (base = NUM2INT(argv[0])) < 0) {
7963 rb_raise(rb_eArgError, "invalid radix %d", base);
7964 }
7965 return rb_str_to_inum(str, base, FALSE);
7966}
7967
7968
7969/*
7970 * call-seq:
7971 * to_f -> float
7972 *
7973 * Returns the result of interpreting leading characters in +self+ as a Float:
7974 *
7975 * '3.14159'.to_f # => 3.14159
7976 * '1.234e-2'.to_f # => 0.01234
7977 *
7978 * Characters past a leading valid number are ignored:
7979 *
7980 * '3.14 (pi to two places)'.to_f # => 3.14
7981 *
7982 * Returns zero if there is no leading valid number:
7983 *
7984 * 'abcdef'.to_f # => 0.0
7985 *
7986 * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
7987 */
7988
7989static VALUE
7990rb_str_to_f(VALUE str)
7991{
7992 return DBL2NUM(rb_str_to_dbl(str, FALSE));
7993}
7994
7995
7996/*
7997 * call-seq:
7998 * to_s -> self or new_string
7999 *
8000 * Returns +self+ if +self+ is a +String+,
8001 * or +self+ converted to a +String+ if +self+ is a subclass of +String+.
8002 *
8003 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8004 */
8005
8006static VALUE
8007rb_str_to_s(VALUE str)
8008{
8009 if (rb_obj_class(str) != rb_cString) {
8010 return str_duplicate(rb_cString, str);
8011 }
8012 return str;
8013}
8014
8015#if 0
8016static void
8017str_cat_char(VALUE str, unsigned int c, rb_encoding *enc)
8018{
8019 char s[RUBY_MAX_CHAR_LEN];
8020 int n = rb_enc_codelen(c, enc);
8021
8022 rb_enc_mbcput(c, s, enc);
8023 rb_enc_str_buf_cat(str, s, n, enc);
8024}
8025#endif
8026
8027#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */
8028
8029int
8030rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p)
8031{
8032 char buf[CHAR_ESC_LEN + 1];
8033 int l;
8034
8035#if SIZEOF_INT > 4
8036 c &= 0xffffffff;
8037#endif
8038 if (unicode_p) {
8039 if (c < 0x7F && ISPRINT(c)) {
8040 snprintf(buf, CHAR_ESC_LEN, "%c", c);
8041 }
8042 else if (c < 0x10000) {
8043 snprintf(buf, CHAR_ESC_LEN, "\\u%04X", c);
8044 }
8045 else {
8046 snprintf(buf, CHAR_ESC_LEN, "\\u{%X}", c);
8047 }
8048 }
8049 else {
8050 if (c < 0x100) {
8051 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", c);
8052 }
8053 else {
8054 snprintf(buf, CHAR_ESC_LEN, "\\x{%X}", c);
8055 }
8056 }
8057 l = (int)strlen(buf); /* CHAR_ESC_LEN cannot exceed INT_MAX */
8058 rb_str_buf_cat(result, buf, l);
8059 return l;
8060}
8061
8062const char *
8063ruby_escaped_char(int c)
8064{
8065 switch (c) {
8066 case '\0': return "\\0";
8067 case '\n': return "\\n";
8068 case '\r': return "\\r";
8069 case '\t': return "\\t";
8070 case '\f': return "\\f";
8071 case '\013': return "\\v";
8072 case '\010': return "\\b";
8073 case '\007': return "\\a";
8074 case '\033': return "\\e";
8075 case '\x7f': return "\\c?";
8076 }
8077 return NULL;
8078}
8079
8080VALUE
8081rb_str_escape(VALUE str)
8082{
8083 int encidx = ENCODING_GET(str);
8084 rb_encoding *enc = rb_enc_from_index(encidx);
8085 const char *p = RSTRING_PTR(str);
8086 const char *pend = RSTRING_END(str);
8087 const char *prev = p;
8088 char buf[CHAR_ESC_LEN + 1];
8089 VALUE result = rb_str_buf_new(0);
8090 int unicode_p = rb_enc_unicode_p(enc);
8091 int asciicompat = rb_enc_asciicompat(enc);
8092
8093 while (p < pend) {
8094 unsigned int c;
8095 const char *cc;
8096 int n = rb_enc_precise_mbclen(p, pend, enc);
8097 if (!MBCLEN_CHARFOUND_P(n)) {
8098 if (p > prev) str_buf_cat(result, prev, p - prev);
8099 n = rb_enc_mbminlen(enc);
8100 if (pend < p + n)
8101 n = (int)(pend - p);
8102 while (n--) {
8103 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
8104 str_buf_cat(result, buf, strlen(buf));
8105 prev = ++p;
8106 }
8107 continue;
8108 }
8109 n = MBCLEN_CHARFOUND_LEN(n);
8110 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8111 p += n;
8112 cc = ruby_escaped_char(c);
8113 if (cc) {
8114 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8115 str_buf_cat(result, cc, strlen(cc));
8116 prev = p;
8117 }
8118 else if (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c)) {
8119 }
8120 else {
8121 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8122 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8123 prev = p;
8124 }
8125 }
8126 if (p > prev) str_buf_cat(result, prev, p - prev);
8127 ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
8128
8129 return result;
8130}
8131
8132/* Lookup table for the inspect fast path. 1 marks bytes that need
8133 * no escaping. 0 marks bytes that need escape inspection: 0x00-0x1F
8134 * (control), 0x22 ("), 0x23 (#), 0x5C (\‍), 0x7F (DEL), 0x80-0xFF
8135 * (non-ASCII). */
8136static const bool inspect_no_escape[256] = {
8137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
8138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
8139 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20-0x2F */
8140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30-0x3F */
8141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F */
8142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 0x50-0x5F */
8143 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F */
8144 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 0x70-0x7F */
8145};
8146
8147/*
8148 * call-seq:
8149 * inspect -> string
8150 *
8151 * :include: doc/string/inspect.rdoc
8152 *
8153 */
8154
8155VALUE
8157{
8158 int encidx = ENCODING_GET(str);
8159 rb_encoding *enc = rb_enc_from_index(encidx);
8160 const char *p, *pend, *prev;
8161 char buf[CHAR_ESC_LEN + 1];
8162 VALUE result = rb_str_buf_new(RSTRING_LEN(str) + 2); /* string content + surrounding quotes */
8163 rb_encoding *resenc = rb_default_internal_encoding();
8164 int unicode_p = rb_enc_unicode_p(enc);
8165 int asciicompat = rb_enc_asciicompat(enc);
8166 int cr = rb_enc_str_coderange(str);
8167
8168 if (resenc == NULL) resenc = rb_default_external_encoding();
8169 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8170 rb_enc_associate(result, resenc);
8171 str_buf_cat2(result, "\"");
8172
8173 p = RSTRING_PTR(str); pend = RSTRING_END(str);
8174 prev = p;
8175 while (p < pend) {
8176 unsigned int c, cc;
8177 int n;
8178
8179 /* Fast path: bulk-skip runs of safe ASCII bytes via a lookup table.
8180 * Only well-formed strings (CR=7BIT for any encoding, or UTF-8 VALID)
8181 * are eligible. */
8182 if (cr == ENC_CODERANGE_7BIT ||
8183 (encidx == ENCINDEX_UTF_8 && cr == ENC_CODERANGE_VALID)) {
8184 while (p < pend && inspect_no_escape[(unsigned char)*p]) p++;
8185 if (p >= pend) break;
8186 }
8187
8188 n = rb_enc_precise_mbclen(p, pend, enc);
8189 if (!MBCLEN_CHARFOUND_P(n)) {
8190 if (p > prev) str_buf_cat(result, prev, p - prev);
8191 n = rb_enc_mbminlen(enc);
8192 if (pend < p + n)
8193 n = (int)(pend - p);
8194 while (n--) {
8195 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
8196 str_buf_cat(result, buf, strlen(buf));
8197 prev = ++p;
8198 }
8199 continue;
8200 }
8201 n = MBCLEN_CHARFOUND_LEN(n);
8202 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8203 p += n;
8204 if ((asciicompat || unicode_p) &&
8205 (c == '"'|| c == '\\' ||
8206 (c == '#' &&
8207 p < pend &&
8208 MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
8209 (cc = rb_enc_codepoint(p,pend,enc),
8210 (cc == '$' || cc == '@' || cc == '{'))))) {
8211 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8212 str_buf_cat2(result, "\\");
8213 if (asciicompat || enc == resenc) {
8214 prev = p - n;
8215 continue;
8216 }
8217 }
8218 switch (c) {
8219 case '\n': cc = 'n'; break;
8220 case '\r': cc = 'r'; break;
8221 case '\t': cc = 't'; break;
8222 case '\f': cc = 'f'; break;
8223 case '\013': cc = 'v'; break;
8224 case '\010': cc = 'b'; break;
8225 case '\007': cc = 'a'; break;
8226 case 033: cc = 'e'; break;
8227 default: cc = 0; break;
8228 }
8229 if (cc) {
8230 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8231 buf[0] = '\\';
8232 buf[1] = (char)cc;
8233 str_buf_cat(result, buf, 2);
8234 prev = p;
8235 continue;
8236 }
8237 /* The special casing of 0x85 (NEXT_LINE) here is because
8238 * Oniguruma historically treats it as printable, but it
8239 * doesn't match the print POSIX bracket class or character
8240 * property in regexps.
8241 *
8242 * See Ruby Bug #16842 for details:
8243 * https://bugs.ruby-lang.org/issues/16842
8244 */
8245 if ((enc == resenc && rb_enc_isprint(c, enc) && c != 0x85) ||
8246 (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c))) {
8247 continue;
8248 }
8249 else {
8250 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8251 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8252 prev = p;
8253 continue;
8254 }
8255 }
8256 if (p > prev) str_buf_cat(result, prev, p - prev);
8257 str_buf_cat2(result, "\"");
8258
8259 return result;
8260}
8261
8262#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8263
8264/*
8265 * call-seq:
8266 * dump -> new_string
8267 *
8268 * :include: doc/string/dump.rdoc
8269 *
8270 */
8271
8272VALUE
8274{
8275 int encidx = rb_enc_get_index(str);
8276 rb_encoding *enc = rb_enc_from_index(encidx);
8277 rb_len_t len;
8278 const char *p, *pend;
8279 char *q, *qend;
8280 VALUE result;
8281 int u8 = (encidx == rb_utf8_encindex());
8282 static const char nonascii_suffix[] = ".dup.force_encoding(\"%s\")";
8283
8284 len = 2; /* "" */
8285 if (!rb_enc_asciicompat(enc)) {
8286 len += strlen(nonascii_suffix) - rb_strlen_lit("%s");
8287 len += strlen(enc->name);
8288 }
8289
8290 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8291 while (p < pend) {
8292 int clen;
8293 unsigned char c = *p++;
8294
8295 switch (c) {
8296 case '"': case '\\':
8297 case '\n': case '\r':
8298 case '\t': case '\f':
8299 case '\013': case '\010': case '\007': case '\033':
8300 clen = 2;
8301 break;
8302
8303 case '#':
8304 clen = IS_EVSTR(p, pend) ? 2 : 1;
8305 break;
8306
8307 default:
8308 if (ISPRINT(c)) {
8309 clen = 1;
8310 }
8311 else {
8312 if (u8 && c > 0x7F) { /* \u notation */
8313 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8314 if (MBCLEN_CHARFOUND_P(n)) {
8315 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8316 if (cc <= 0xFFFF)
8317 clen = 6; /* \uXXXX */
8318 else if (cc <= 0xFFFFF)
8319 clen = 9; /* \u{XXXXX} */
8320 else
8321 clen = 10; /* \u{XXXXXX} */
8322 p += MBCLEN_CHARFOUND_LEN(n)-1;
8323 break;
8324 }
8325 }
8326 clen = 4; /* \xNN */
8327 }
8328 break;
8329 }
8330
8331 if (clen > RB_LEN_MAX - len) {
8332 rb_raise(rb_eRuntimeError, "string size too big");
8333 }
8334 len += clen;
8335 }
8336
8337 result = rb_str_new(0, len);
8338 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8339 q = RSTRING_PTR(result); qend = q + len + 1;
8340
8341 *q++ = '"';
8342 while (p < pend) {
8343 unsigned char c = *p++;
8344
8345 if (c == '"' || c == '\\') {
8346 *q++ = '\\';
8347 *q++ = c;
8348 }
8349 else if (c == '#') {
8350 if (IS_EVSTR(p, pend)) *q++ = '\\';
8351 *q++ = '#';
8352 }
8353 else if (c == '\n') {
8354 *q++ = '\\';
8355 *q++ = 'n';
8356 }
8357 else if (c == '\r') {
8358 *q++ = '\\';
8359 *q++ = 'r';
8360 }
8361 else if (c == '\t') {
8362 *q++ = '\\';
8363 *q++ = 't';
8364 }
8365 else if (c == '\f') {
8366 *q++ = '\\';
8367 *q++ = 'f';
8368 }
8369 else if (c == '\013') {
8370 *q++ = '\\';
8371 *q++ = 'v';
8372 }
8373 else if (c == '\010') {
8374 *q++ = '\\';
8375 *q++ = 'b';
8376 }
8377 else if (c == '\007') {
8378 *q++ = '\\';
8379 *q++ = 'a';
8380 }
8381 else if (c == '\033') {
8382 *q++ = '\\';
8383 *q++ = 'e';
8384 }
8385 else if (ISPRINT(c)) {
8386 *q++ = c;
8387 }
8388 else {
8389 *q++ = '\\';
8390 if (u8) {
8391 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8392 if (MBCLEN_CHARFOUND_P(n)) {
8393 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8394 p += n;
8395 if (cc <= 0xFFFF)
8396 snprintf(q, qend-q, "u%04X", cc); /* \uXXXX */
8397 else
8398 snprintf(q, qend-q, "u{%X}", cc); /* \u{XXXXX} or \u{XXXXXX} */
8399 q += strlen(q);
8400 continue;
8401 }
8402 }
8403 snprintf(q, qend-q, "x%02X", c);
8404 q += 3;
8405 }
8406 }
8407 *q++ = '"';
8408 *q = '\0';
8409 if (!rb_enc_asciicompat(enc)) {
8410 snprintf(q, qend-q, nonascii_suffix, enc->name);
8411 encidx = rb_ascii8bit_encindex();
8412 }
8413 /* result from dump is ASCII */
8414 rb_enc_associate_index(result, encidx);
8416 return result;
8417}
8418
8419static int
8420unescape_ascii(unsigned int c)
8421{
8422 switch (c) {
8423 case 'n':
8424 return '\n';
8425 case 'r':
8426 return '\r';
8427 case 't':
8428 return '\t';
8429 case 'f':
8430 return '\f';
8431 case 'v':
8432 return '\13';
8433 case 'b':
8434 return '\010';
8435 case 'a':
8436 return '\007';
8437 case 'e':
8438 return 033;
8439 }
8441}
8442
8443static void
8444undump_after_backslash(VALUE undumped, const char **ss, const char *s_end, rb_encoding **penc, bool *utf8, bool *binary)
8445{
8446 const char *s = *ss;
8447 unsigned int c;
8448 int codelen;
8449 size_t hexlen;
8450 unsigned char buf[6];
8451 static rb_encoding *enc_utf8 = NULL;
8452
8453 switch (*s) {
8454 case '\\':
8455 case '"':
8456 case '#':
8457 rb_str_cat(undumped, s, 1); /* cat itself */
8458 s++;
8459 break;
8460 case 'n':
8461 case 'r':
8462 case 't':
8463 case 'f':
8464 case 'v':
8465 case 'b':
8466 case 'a':
8467 case 'e':
8468 *buf = unescape_ascii(*s);
8469 rb_str_cat(undumped, (char *)buf, 1);
8470 s++;
8471 break;
8472 case 'u':
8473 if (*binary) {
8474 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8475 }
8476 *utf8 = true;
8477 if (++s >= s_end) {
8478 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8479 }
8480 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8481 if (*penc != enc_utf8) {
8482 *penc = enc_utf8;
8483 rb_enc_associate(undumped, enc_utf8);
8484 }
8485 if (*s == '{') { /* handle \u{...} form */
8486 s++;
8487 for (;;) {
8488 if (s >= s_end) {
8489 rb_raise(rb_eRuntimeError, "unterminated Unicode escape");
8490 }
8491 if (*s == '}') {
8492 s++;
8493 break;
8494 }
8495 if (ISSPACE(*s)) {
8496 s++;
8497 continue;
8498 }
8499 c = scan_hex(s, s_end-s, &hexlen);
8500 if (hexlen == 0 || hexlen > 6) {
8501 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8502 }
8503 if (c > 0x10ffff) {
8504 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint (too large)");
8505 }
8506 if (0xd800 <= c && c <= 0xdfff) {
8507 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8508 }
8509 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8510 rb_str_cat(undumped, (char *)buf, codelen);
8511 s += hexlen;
8512 }
8513 }
8514 else { /* handle \uXXXX form */
8515 c = scan_hex(s, 4, &hexlen);
8516 if (hexlen != 4) {
8517 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8518 }
8519 if (0xd800 <= c && c <= 0xdfff) {
8520 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8521 }
8522 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8523 rb_str_cat(undumped, (char *)buf, codelen);
8524 s += hexlen;
8525 }
8526 break;
8527 case 'x':
8528 if (++s >= s_end) {
8529 rb_raise(rb_eRuntimeError, "invalid hex escape");
8530 }
8531 *buf = scan_hex(s, 2, &hexlen);
8532 if (hexlen != 2) {
8533 rb_raise(rb_eRuntimeError, "invalid hex escape");
8534 }
8535 if (!ISASCII(*buf)) {
8536 if (*utf8) {
8537 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8538 }
8539 *binary = true;
8540 }
8541 rb_str_cat(undumped, (char *)buf, 1);
8542 s += hexlen;
8543 break;
8544 default:
8545 rb_str_cat(undumped, s-1, 2);
8546 s++;
8547 }
8548
8549 *ss = s;
8550}
8551
8552static VALUE rb_str_is_ascii_only_p(VALUE str);
8553
8554/*
8555 * call-seq:
8556 * undump -> new_string
8557 *
8558 * Inverse of String#dump; returns a copy of +self+ with changes of the kinds made by String#dump "undone."
8559 *
8560 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8561 */
8562
8563static VALUE
8564str_undump(VALUE str)
8565{
8566 const char *s = RSTRING_PTR(str);
8567 const char *s_end = RSTRING_END(str);
8568 rb_encoding *enc = rb_enc_get(str);
8569 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8570 bool utf8 = false;
8571 bool binary = false;
8572 int w;
8573
8575 if (rb_str_is_ascii_only_p(str) == Qfalse) {
8576 rb_raise(rb_eRuntimeError, "non-ASCII character detected");
8577 }
8578 if (!str_null_check(str, &w)) {
8579 rb_raise(rb_eRuntimeError, "string contains null byte");
8580 }
8581 if (RSTRING_LEN(str) < 2) goto invalid_format;
8582 if (*s != '"') goto invalid_format;
8583
8584 /* strip '"' at the start */
8585 s++;
8586
8587 for (;;) {
8588 if (s >= s_end) {
8589 rb_raise(rb_eRuntimeError, "unterminated dumped string");
8590 }
8591
8592 if (*s == '"') {
8593 /* epilogue */
8594 s++;
8595 if (s == s_end) {
8596 /* ascii compatible dumped string */
8597 break;
8598 }
8599 else {
8600 static const char force_encoding_suffix[] = ".force_encoding(\""; /* "\")" */
8601 static const char dup_suffix[] = ".dup";
8602 const char *encname;
8603 int encidx;
8604 ptrdiff_t size;
8605
8606 /* check separately for strings dumped by older versions */
8607 size = sizeof(dup_suffix) - 1;
8608 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8609
8610 size = sizeof(force_encoding_suffix) - 1;
8611 if (s_end - s <= size) goto invalid_format;
8612 if (memcmp(s, force_encoding_suffix, size) != 0) goto invalid_format;
8613 s += size;
8614
8615 if (utf8) {
8616 rb_raise(rb_eRuntimeError, "dumped string contained Unicode escape but used force_encoding");
8617 }
8618
8619 encname = s;
8620 s = memchr(s, '"', s_end-s);
8621 size = s - encname;
8622 if (!s) goto invalid_format;
8623 if (s_end - s != 2) goto invalid_format;
8624 if (s[0] != '"' || s[1] != ')') goto invalid_format;
8625
8626 encidx = rb_enc_find_index2(encname, (rb_len_t)size);
8627 if (encidx < 0) {
8628 rb_raise(rb_eRuntimeError, "dumped string has unknown encoding name");
8629 }
8630 rb_enc_associate_index(undumped, encidx);
8631 }
8632 break;
8633 }
8634
8635 if (*s == '\\') {
8636 s++;
8637 if (s >= s_end) {
8638 rb_raise(rb_eRuntimeError, "invalid escape");
8639 }
8640 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8641 }
8642 else {
8643 rb_str_cat(undumped, s++, 1);
8644 }
8645 }
8646
8647 RB_GC_GUARD(str);
8648
8649 return undumped;
8650invalid_format:
8651 rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8652}
8653
8654static void
8655rb_str_check_dummy_enc(rb_encoding *enc)
8656{
8657 if (rb_enc_dummy_p(enc)) {
8658 rb_raise(rb_eEncCompatError, "incompatible encoding with this operation: %s",
8659 rb_enc_name(enc));
8660 }
8661}
8662
8663static rb_encoding *
8664str_true_enc(VALUE str)
8665{
8666 rb_encoding *enc = STR_ENC_GET(str);
8667 rb_str_check_dummy_enc(enc);
8668 return enc;
8669}
8670
8671static OnigCaseFoldType
8672check_case_options(int argc, VALUE *argv, OnigCaseFoldType flags)
8673{
8674 if (argc==0)
8675 return flags;
8676 if (argc>2)
8677 rb_raise(rb_eArgError, "too many options");
8678 if (argv[0]==sym_turkic) {
8679 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8680 if (argc==2) {
8681 if (argv[1]==sym_lithuanian)
8682 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8683 else
8684 rb_raise(rb_eArgError, "invalid second option");
8685 }
8686 }
8687 else if (argv[0]==sym_lithuanian) {
8688 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8689 if (argc==2) {
8690 if (argv[1]==sym_turkic)
8691 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8692 else
8693 rb_raise(rb_eArgError, "invalid second option");
8694 }
8695 }
8696 else if (argc>1)
8697 rb_raise(rb_eArgError, "too many options");
8698 else if (argv[0]==sym_ascii)
8699 flags |= ONIGENC_CASE_ASCII_ONLY;
8700 else if (argv[0]==sym_fold) {
8701 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8702 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8703 else
8704 rb_raise(rb_eArgError, "option :fold only allowed for downcasing");
8705 }
8706 else
8707 rb_raise(rb_eArgError, "invalid option");
8708 return flags;
8709}
8710
8711static inline bool
8712case_option_single_p(OnigCaseFoldType flags, rb_encoding *enc, VALUE str)
8713{
8714 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() || rb_enc_mbmaxlen(enc) == 1))
8715 return true;
8716 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8717 (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT || rb_is_ascii8bit_enc(enc));
8718}
8719
8720/* 16 should be long enough to absorb any kind of single character length increase */
8721#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8722#ifndef CASEMAP_DEBUG
8723# define CASEMAP_DEBUG 0
8724#endif
8725
8726struct mapping_buffer;
8727typedef struct mapping_buffer {
8728 size_t capa;
8729 size_t used;
8730 struct mapping_buffer *next;
8731 OnigUChar space[FLEX_ARY_LEN];
8733
8734static void
8735mapping_buffer_free(void *p)
8736{
8737 mapping_buffer *previous_buffer;
8738 mapping_buffer *current_buffer = p;
8739 while (current_buffer) {
8740 previous_buffer = current_buffer;
8741 current_buffer = current_buffer->next;
8742 ruby_xfree_sized(previous_buffer, offsetof(mapping_buffer, space) + previous_buffer->capa);
8743 }
8744}
8745
8746static const rb_data_type_t mapping_buffer_type = {
8747 "mapping_buffer",
8748 {0, mapping_buffer_free,},
8749 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8750};
8751
8752static VALUE
8753rb_str_casemap(VALUE source, OnigCaseFoldType *flags, rb_encoding *enc)
8754{
8755 VALUE target;
8756
8757 const OnigUChar *source_current, *source_end;
8758 int target_length = 0;
8759 VALUE buffer_anchor;
8760 mapping_buffer *current_buffer = 0;
8761 mapping_buffer **pre_buffer;
8762 size_t buffer_count = 0;
8763 int buffer_length_or_invalid;
8764
8765 if (RSTRING_LEN(source) == 0) return str_duplicate(rb_cString, source);
8766
8767 source_current = (OnigUChar*)RSTRING_PTR(source);
8768 source_end = (OnigUChar*)RSTRING_END(source);
8769
8770 buffer_anchor = TypedData_Wrap_Struct(0, &mapping_buffer_type, 0);
8771 pre_buffer = (mapping_buffer **)&DATA_PTR(buffer_anchor);
8772 while (source_current < source_end) {
8773 /* increase multiplier using buffer count to converge quickly */
8774 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8775 if (CASEMAP_DEBUG) {
8776 fprintf(stderr, "Buffer allocation, capa is %"PRIuSIZE"\n", capa); /* for tuning */
8777 }
8778 current_buffer = xmalloc(offsetof(mapping_buffer, space) + capa);
8779 *pre_buffer = current_buffer;
8780 pre_buffer = &current_buffer->next;
8781 current_buffer->next = NULL;
8782 current_buffer->capa = capa;
8783 buffer_length_or_invalid = enc->case_map(flags,
8784 &source_current, source_end,
8785 current_buffer->space,
8786 current_buffer->space+current_buffer->capa,
8787 enc);
8788 if (buffer_length_or_invalid < 0) {
8789 current_buffer = DATA_PTR(buffer_anchor);
8790 DATA_PTR(buffer_anchor) = 0;
8791 mapping_buffer_free(current_buffer);
8792 rb_raise(rb_eArgError, "input string invalid");
8793 }
8794 target_length += current_buffer->used = buffer_length_or_invalid;
8795 }
8796 if (CASEMAP_DEBUG) {
8797 fprintf(stderr, "Buffer count is %"PRIuSIZE"\n", buffer_count); /* for tuning */
8798 }
8799
8800 if (buffer_count==1) {
8801 target = rb_str_new((const char*)current_buffer->space, target_length);
8802 }
8803 else {
8804 char *target_current;
8805
8806 target = rb_str_new(0, target_length);
8807 target_current = RSTRING_PTR(target);
8808 current_buffer = DATA_PTR(buffer_anchor);
8809 while (current_buffer) {
8810 memcpy(target_current, current_buffer->space, current_buffer->used);
8811 target_current += current_buffer->used;
8812 current_buffer = current_buffer->next;
8813 }
8814 }
8815 current_buffer = DATA_PTR(buffer_anchor);
8816 DATA_PTR(buffer_anchor) = 0;
8817 mapping_buffer_free(current_buffer);
8818
8819 RB_GC_GUARD(buffer_anchor);
8820
8821 /* TODO: check about string terminator character */
8822 str_enc_copy_direct(target, source);
8823 /*ENC_CODERANGE_SET(mapped, cr);*/
8824
8825 return target;
8826}
8827
8828static VALUE
8829rb_str_ascii_casemap(VALUE source, VALUE target, OnigCaseFoldType *flags, rb_encoding *enc)
8830{
8831 const OnigUChar *source_current, *source_end;
8832 OnigUChar *target_current, *target_end;
8833 rb_len_t old_length = RSTRING_LEN(source);
8834 int length_or_invalid;
8835
8836 if (old_length == 0) return Qnil;
8837
8838 source_current = (OnigUChar*)RSTRING_PTR(source);
8839 source_end = (OnigUChar*)RSTRING_END(source);
8840 if (source == target) {
8841 target_current = (OnigUChar*)source_current;
8842 target_end = (OnigUChar*)source_end;
8843 }
8844 else {
8845 target_current = (OnigUChar*)RSTRING_PTR(target);
8846 target_end = (OnigUChar*)RSTRING_END(target);
8847 }
8848
8849 length_or_invalid = onigenc_ascii_only_case_map(flags,
8850 &source_current, source_end,
8851 target_current, target_end, enc);
8852 if (length_or_invalid < 0)
8853 rb_raise(rb_eArgError, "input string invalid");
8854 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8855 fprintf(stderr, "problem with rb_str_ascii_casemap"
8856 "; old_length=%"PRIdLEN", new_length=%d\n", old_length, length_or_invalid);
8857 rb_raise(rb_eArgError, "internal problem with rb_str_ascii_casemap"
8858 "; old_length=%"PRIdLEN", new_length=%d\n", old_length, length_or_invalid);
8859 }
8860
8861 str_enc_copy(target, source);
8862
8863 return target;
8864}
8865
8866static bool
8867upcase_single(VALUE str)
8868{
8869 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8870 bool modified = false;
8871
8872 while (s < send) {
8873 unsigned int c = *(unsigned char*)s;
8874
8875 if ('a' <= c && c <= 'z') {
8876 *s = 'A' + (c - 'a');
8877 modified = true;
8878 }
8879 s++;
8880 }
8881 return modified;
8882}
8883
8884/*
8885 * call-seq:
8886 * upcase!(mapping) -> self or nil
8887 *
8888 * Like String#upcase, except that:
8889 *
8890 * - Changes character casings in +self+ (not in a copy of +self+).
8891 * - Returns +self+ if any changes are made, +nil+ otherwise.
8892 *
8893 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8894 */
8895
8896static VALUE
8897rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
8898{
8899 rb_encoding *enc;
8900 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8901
8902 flags = check_case_options(argc, argv, flags);
8903 str_modify_keep_cr(str);
8904 enc = str_true_enc(str);
8905 if (case_option_single_p(flags, enc, str)) {
8906 if (upcase_single(str))
8907 flags |= ONIGENC_CASE_MODIFIED;
8908 }
8909 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8910 rb_str_ascii_casemap(str, str, &flags, enc);
8911 else
8912 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8913
8914 if (ONIGENC_CASE_MODIFIED&flags) return str;
8915 return Qnil;
8916}
8917
8918
8919/*
8920 * call-seq:
8921 * upcase(mapping = :ascii) -> new_string
8922 *
8923 * :include: doc/string/upcase.rdoc
8924 */
8925
8926static VALUE
8927rb_str_upcase(int argc, VALUE *argv, VALUE str)
8928{
8929 rb_encoding *enc;
8930 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8931 VALUE ret;
8932
8933 flags = check_case_options(argc, argv, flags);
8934 enc = str_true_enc(str);
8935 if (case_option_single_p(flags, enc, str)) {
8936 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8937 str_enc_copy_direct(ret, str);
8938 upcase_single(ret);
8939 }
8940 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8941 ret = rb_str_new(0, RSTRING_LEN(str));
8942 rb_str_ascii_casemap(str, ret, &flags, enc);
8943 }
8944 else {
8945 ret = rb_str_casemap(str, &flags, enc);
8946 }
8947
8948 return ret;
8949}
8950
8951static bool
8952downcase_single(VALUE str)
8953{
8954 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8955 bool modified = false;
8956
8957 while (s < send) {
8958 unsigned int c = *(unsigned char*)s;
8959
8960 if ('A' <= c && c <= 'Z') {
8961 *s = 'a' + (c - 'A');
8962 modified = true;
8963 }
8964 s++;
8965 }
8966
8967 return modified;
8968}
8969
8970/*
8971 * call-seq:
8972 * downcase!(mapping) -> self or nil
8973 *
8974 * Like String#downcase, except that:
8975 *
8976 * - Changes character casings in +self+ (not in a copy of +self+).
8977 * - Returns +self+ if any changes are made, +nil+ otherwise.
8978 *
8979 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8980 */
8981
8982static VALUE
8983rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
8984{
8985 rb_encoding *enc;
8986 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8987
8988 flags = check_case_options(argc, argv, flags);
8989 str_modify_keep_cr(str);
8990 enc = str_true_enc(str);
8991 if (case_option_single_p(flags, enc, str)) {
8992 if (downcase_single(str))
8993 flags |= ONIGENC_CASE_MODIFIED;
8994 }
8995 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8996 rb_str_ascii_casemap(str, str, &flags, enc);
8997 else
8998 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8999
9000 if (ONIGENC_CASE_MODIFIED&flags) return str;
9001 return Qnil;
9002}
9003
9004
9005/*
9006 * call-seq:
9007 * downcase(mapping = :ascii) -> new_string
9008 *
9009 * :include: doc/string/downcase.rdoc
9010 *
9011 */
9012
9013static VALUE
9014rb_str_downcase(int argc, VALUE *argv, VALUE str)
9015{
9016 rb_encoding *enc;
9017 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9018 VALUE ret;
9019
9020 flags = check_case_options(argc, argv, flags);
9021 enc = str_true_enc(str);
9022 if (case_option_single_p(flags, enc, str)) {
9023 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9024 str_enc_copy_direct(ret, str);
9025 downcase_single(ret);
9026 }
9027 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9028 ret = rb_str_new(0, RSTRING_LEN(str));
9029 rb_str_ascii_casemap(str, ret, &flags, enc);
9030 }
9031 else {
9032 ret = rb_str_casemap(str, &flags, enc);
9033 }
9034
9035 return ret;
9036}
9037
9038static bool
9039capitalize_single(VALUE str)
9040{
9041 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
9042 bool modified = false;
9043
9044 if (s < send) {
9045 unsigned int c = (unsigned char)*s;
9046
9047 if ('a' <= c && c <= 'z') {
9048 *s = 'A' + (c - 'a');
9049 modified = true;
9050 }
9051 s++;
9052 }
9053 while (s < send) {
9054 unsigned int c = (unsigned char)*s;
9055
9056 if ('A' <= c && c <= 'Z') {
9057 *s = 'a' + (c - 'A');
9058 modified = true;
9059 }
9060 s++;
9061 }
9062
9063 return modified;
9064}
9065
9066/*
9067 * call-seq:
9068 * capitalize!(mapping = :ascii) -> self or nil
9069 *
9070 * Like String#capitalize, except that:
9071 *
9072 * - Changes character casings in +self+ (not in a copy of +self+).
9073 * - Returns +self+ if any changes are made, +nil+ otherwise.
9074 *
9075 * Related: See {Modifying}[rdoc-ref:String@Modifying].
9076 */
9077
9078static VALUE
9079rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
9080{
9081 rb_encoding *enc;
9082 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9083
9084 flags = check_case_options(argc, argv, flags);
9085 str_modify_keep_cr(str);
9086 enc = str_true_enc(str);
9087 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
9088 if (case_option_single_p(flags, enc, str)) {
9089 if (capitalize_single(str))
9090 flags |= ONIGENC_CASE_MODIFIED;
9091 }
9092 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9093 rb_str_ascii_casemap(str, str, &flags, enc);
9094 else
9095 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9096
9097 if (ONIGENC_CASE_MODIFIED&flags) return str;
9098 return Qnil;
9099}
9100
9101
9102/*
9103 * call-seq:
9104 * capitalize(mapping = :ascii) -> new_string
9105 *
9106 * :include: doc/string/capitalize.rdoc
9107 *
9108 */
9109
9110static VALUE
9111rb_str_capitalize(int argc, VALUE *argv, VALUE str)
9112{
9113 rb_encoding *enc;
9114 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9115 VALUE ret;
9116
9117 flags = check_case_options(argc, argv, flags);
9118 enc = str_true_enc(str);
9119 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str;
9120 if (case_option_single_p(flags, enc, str)) {
9121 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9122 str_enc_copy_direct(ret, str);
9123 capitalize_single(ret);
9124 }
9125 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9126 ret = rb_str_new(0, RSTRING_LEN(str));
9127 rb_str_ascii_casemap(str, ret, &flags, enc);
9128 }
9129 else {
9130 ret = rb_str_casemap(str, &flags, enc);
9131 }
9132 return ret;
9133}
9134
9135
9136/*
9137 * call-seq:
9138 * swapcase!(mapping) -> self or nil
9139 *
9140 * Like String#swapcase, except that:
9141 *
9142 * - Changes are made to +self+, not to copy of +self+.
9143 * - Returns +self+ if any changes are made, +nil+ otherwise.
9144 *
9145 * Related: see {Modifying}[rdoc-ref:String@Modifying].
9146 */
9147
9148static VALUE
9149rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
9150{
9151 rb_encoding *enc;
9152 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9153
9154 flags = check_case_options(argc, argv, flags);
9155 str_modify_keep_cr(str);
9156 enc = str_true_enc(str);
9157 if (flags&ONIGENC_CASE_ASCII_ONLY)
9158 rb_str_ascii_casemap(str, str, &flags, enc);
9159 else
9160 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9161
9162 if (ONIGENC_CASE_MODIFIED&flags) return str;
9163 return Qnil;
9164}
9165
9166
9167/*
9168 * call-seq:
9169 * swapcase(mapping = :ascii) -> new_string
9170 *
9171 * :include: doc/string/swapcase.rdoc
9172 *
9173 */
9174
9175static VALUE
9176rb_str_swapcase(int argc, VALUE *argv, VALUE str)
9177{
9178 rb_encoding *enc;
9179 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9180 VALUE ret;
9181
9182 flags = check_case_options(argc, argv, flags);
9183 enc = str_true_enc(str);
9184 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str_duplicate(rb_cString, str);
9185 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9186 ret = rb_str_new(0, RSTRING_LEN(str));
9187 rb_str_ascii_casemap(str, ret, &flags, enc);
9188 }
9189 else {
9190 ret = rb_str_casemap(str, &flags, enc);
9191 }
9192 return ret;
9193}
9194
9195typedef unsigned char *USTR;
9196
9197struct tr {
9198 int gen;
9199 unsigned int now, max;
9200 const char *p, *pend;
9201};
9202
9203static unsigned int
9204trnext(struct tr *t, rb_encoding *enc)
9205{
9206 int n;
9207
9208 for (;;) {
9209 nextpart:
9210 if (!t->gen) {
9211 if (t->p == t->pend) return -1;
9212 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '\\' && t->p + n < t->pend) {
9213 t->p += n;
9214 }
9215 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9216 t->p += n;
9217 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '-' && t->p + n < t->pend) {
9218 t->p += n;
9219 if (t->p < t->pend) {
9220 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9221 t->p += n;
9222 if (t->now > c) {
9223 if (t->now < 0x80 && c < 0x80) {
9224 rb_raise(rb_eArgError,
9225 "invalid range \"%c-%c\" in string transliteration",
9226 t->now, c);
9227 }
9228 else {
9229 rb_raise(rb_eArgError, "invalid range in string transliteration");
9230 }
9231 continue; /* not reached */
9232 }
9233 else if (t->now < c) {
9234 t->gen = 1;
9235 t->max = c;
9236 }
9237 }
9238 }
9239 return t->now;
9240 }
9241 else {
9242 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9243 if (t->now == t->max) {
9244 t->gen = 0;
9245 goto nextpart;
9246 }
9247 }
9248 if (t->now < t->max) {
9249 return t->now;
9250 }
9251 else {
9252 t->gen = 0;
9253 return t->max;
9254 }
9255 }
9256 }
9257}
9258
9259static VALUE rb_str_delete_bang(int,VALUE*,VALUE);
9260
9261static VALUE
9262tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
9263{
9264 const unsigned int errc = -1;
9265 unsigned int trans[256];
9266 rb_encoding *enc, *e1, *e2;
9267 struct tr trsrc, trrepl;
9268 int cflag = 0;
9269 unsigned int c, c0, last = 0;
9270 int modify = 0, i, l;
9271 unsigned char *s, *send;
9272 VALUE hash = 0;
9273 int singlebyte = single_byte_optimizable(str);
9274 int termlen;
9275 int cr;
9276
9277#define CHECK_IF_ASCII(c) \
9278 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9279 (cr = ENC_CODERANGE_VALID) : 0)
9280
9281 StringValue(src);
9282 StringValue(repl);
9283 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
9284 if (RSTRING_LEN(repl) == 0) {
9285 return rb_str_delete_bang(1, &src, str);
9286 }
9287
9288 cr = ENC_CODERANGE(str);
9289 e1 = rb_enc_check(str, src);
9290 e2 = rb_enc_check(str, repl);
9291 if (e1 == e2) {
9292 enc = e1;
9293 }
9294 else {
9295 enc = rb_enc_check(src, repl);
9296 }
9297 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9298 if (RSTRING_LEN(src) > 1 &&
9299 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) == '^' &&
9300 trsrc.p + l < trsrc.pend) {
9301 cflag = 1;
9302 trsrc.p += l;
9303 }
9304 trrepl.p = RSTRING_PTR(repl);
9305 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9306 trsrc.gen = trrepl.gen = 0;
9307 trsrc.now = trrepl.now = 0;
9308 trsrc.max = trrepl.max = 0;
9309
9310 if (cflag) {
9311 for (i=0; i<256; i++) {
9312 trans[i] = 1;
9313 }
9314 while ((c = trnext(&trsrc, enc)) != errc) {
9315 if (c < 256) {
9316 trans[c] = errc;
9317 }
9318 else {
9319 if (!hash) hash = rb_hash_new();
9320 rb_hash_aset(hash, UINT2NUM(c), Qtrue);
9321 }
9322 }
9323 while ((c = trnext(&trrepl, enc)) != errc)
9324 /* retrieve last replacer */;
9325 last = trrepl.now;
9326 for (i=0; i<256; i++) {
9327 if (trans[i] != errc) {
9328 trans[i] = last;
9329 }
9330 }
9331 }
9332 else {
9333 unsigned int r;
9334
9335 for (i=0; i<256; i++) {
9336 trans[i] = errc;
9337 }
9338 while ((c = trnext(&trsrc, enc)) != errc) {
9339 r = trnext(&trrepl, enc);
9340 if (r == errc) r = trrepl.now;
9341 if (c < 256) {
9342 trans[c] = r;
9343 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9344 }
9345 else {
9346 if (!hash) hash = rb_hash_new();
9347 rb_hash_aset(hash, UINT2NUM(c), UINT2NUM(r));
9348 }
9349 }
9350 }
9351
9352 if (cr == ENC_CODERANGE_VALID && rb_enc_asciicompat(e1))
9353 cr = ENC_CODERANGE_7BIT;
9354 str_modify_keep_cr(str);
9355 s = (unsigned char *)RSTRING_PTR(str); send = (unsigned char *)RSTRING_END(str);
9356 termlen = rb_enc_mbminlen(enc);
9357 if (sflag) {
9358 int clen, tlen;
9359 rb_len_t offset, max = RSTRING_LEN(str);
9360 unsigned int save = -1;
9361 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9362
9363 while (s < send) {
9364 int may_modify = 0;
9365
9366 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9367 if (!MBCLEN_CHARFOUND_P(r)) {
9368 SIZED_FREE_N(buf, max + termlen);
9369 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9370 }
9371 clen = MBCLEN_CHARFOUND_LEN(r);
9372 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9373
9374 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9375
9376 s += clen;
9377 if (c < 256) {
9378 c = trans[c];
9379 }
9380 else if (hash) {
9381 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9382 if (NIL_P(tmp)) {
9383 if (cflag) c = last;
9384 else c = errc;
9385 }
9386 else if (cflag) c = errc;
9387 else c = NUM2INT(tmp);
9388 }
9389 else {
9390 c = errc;
9391 }
9392 if (c != (unsigned int)-1) {
9393 if (save == c) {
9394 CHECK_IF_ASCII(c);
9395 continue;
9396 }
9397 save = c;
9398 tlen = rb_enc_codelen(c, enc);
9399 modify = 1;
9400 }
9401 else {
9402 save = -1;
9403 c = c0;
9404 if (enc != e1) may_modify = 1;
9405 }
9406 if ((offset = t - buf) + tlen > max) {
9407 size_t MAYBE_UNUSED(old) = max + termlen;
9408 max = offset + tlen + (send - s);
9409 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9410 t = buf + offset;
9411 }
9412 rb_enc_mbcput(c, t, enc);
9413 if (may_modify && memcmp(s, t, tlen) != 0) {
9414 modify = 1;
9415 }
9416 CHECK_IF_ASCII(c);
9417 t += tlen;
9418 }
9419 if (!STR_EMBED_P(str)) {
9420 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9421 }
9422 TERM_FILL((char *)t, termlen);
9423 RSTRING(str)->as.heap.ptr = (char *)buf;
9424 STR_SET_LEN(str, t - buf);
9425 STR_SET_NOEMBED(str);
9426 RSTRING(str)->as.heap.aux.capa = max;
9427 }
9428 else if (rb_enc_mbmaxlen(enc) == 1 || (singlebyte && !hash)) {
9429 while (s < send) {
9430 c = (unsigned char)*s;
9431 if (trans[c] != errc) {
9432 if (!cflag) {
9433 c = trans[c];
9434 *s = c;
9435 modify = 1;
9436 }
9437 else {
9438 *s = last;
9439 modify = 1;
9440 }
9441 }
9442 CHECK_IF_ASCII(c);
9443 s++;
9444 }
9445 }
9446 else {
9447 int clen, tlen;
9448 rb_len_t offset, max = (rb_len_t)((send - s) * 1.2);
9449 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9450
9451 while (s < send) {
9452 int may_modify = 0;
9453
9454 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9455 if (!MBCLEN_CHARFOUND_P(r)) {
9456 SIZED_FREE_N(buf, max + termlen);
9457 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9458 }
9459 clen = MBCLEN_CHARFOUND_LEN(r);
9460 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9461
9462 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9463
9464 if (c < 256) {
9465 c = trans[c];
9466 }
9467 else if (hash) {
9468 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9469 if (NIL_P(tmp)) {
9470 if (cflag) c = last;
9471 else c = errc;
9472 }
9473 else if (cflag) c = errc;
9474 else c = NUM2INT(tmp);
9475 }
9476 else {
9477 c = cflag ? last : errc;
9478 }
9479 if (c != errc) {
9480 tlen = rb_enc_codelen(c, enc);
9481 modify = 1;
9482 }
9483 else {
9484 c = c0;
9485 if (enc != e1) may_modify = 1;
9486 }
9487 if ((offset = t - buf) + tlen > max) {
9488 size_t MAYBE_UNUSED(old) = max + termlen;
9489 max = offset + tlen + (rb_len_t)((send - s) * 1.2);
9490 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9491 t = buf + offset;
9492 }
9493
9494 rb_enc_mbcput(c, t, enc);
9495 if (may_modify && memcmp(s, t, tlen) != 0) {
9496 modify = 1;
9497 }
9498 CHECK_IF_ASCII(c);
9499 s += clen;
9500 t += tlen;
9501 }
9502 if (!STR_EMBED_P(str)) {
9503 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9504 }
9505 TERM_FILL((char *)t, termlen);
9506 RSTRING(str)->as.heap.ptr = (char *)buf;
9507 STR_SET_LEN(str, t - buf);
9508 STR_SET_NOEMBED(str);
9509 RSTRING(str)->as.heap.aux.capa = max;
9510 }
9511
9512 if (modify) {
9513 if (cr != ENC_CODERANGE_BROKEN)
9514 ENC_CODERANGE_SET(str, cr);
9515 rb_enc_associate(str, enc);
9516 return str;
9517 }
9518 return Qnil;
9519}
9520
9522 unsigned char *buf;
9523 unsigned char *ptr;
9524 size_t capa;
9525 size_t initial_capa;
9526};
9527
9528static inline void
9529tr_buffer_init(struct tr_buffer *buffer, size_t initial_capa)
9530{
9531 if (initial_capa < 32) {
9532 initial_capa = 32;
9533 }
9534 *buffer = (struct tr_buffer){ .initial_capa = initial_capa };
9535}
9536
9537static inline void
9538tr_buffer_ensure_capa(struct tr_buffer *buffer, size_t extra_capa)
9539{
9540 size_t offset = buffer->ptr - buffer->buf;
9541 size_t required_capa = offset + extra_capa;
9542 if (UNLIKELY(buffer->capa < required_capa)) {
9543 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9544 RUBY_ASSERT(new_capa >= 32); // Lower would cause infinite loop
9545 while (new_capa < required_capa) {
9546 new_capa = (size_t)(new_capa * 1.2);
9547 }
9548 SIZED_REALLOC_N(buffer->buf, unsigned char, new_capa, buffer->capa);
9549 buffer->ptr = buffer->buf + offset;
9550 buffer->capa = new_capa;
9551 }
9552}
9553
9554static inline void
9555tr_buffer_append(struct tr_buffer *buffer, const unsigned char *ptr, size_t len)
9556{
9557 if (len) {
9558 tr_buffer_ensure_capa(buffer, len);
9559 memcpy(buffer->ptr, ptr, len);
9560 buffer->ptr += len;
9561 }
9562}
9563
9564static inline void
9565tr_buffer_append_str(struct tr_buffer *buffer, VALUE str)
9566{
9567 tr_buffer_append(buffer, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9568}
9569
9570static inline void
9571tr_buffer_mbcput(struct tr_buffer *buffer, int codepoint, rb_encoding *enc)
9572{
9573 tr_buffer_ensure_capa(buffer, 4);
9574 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9575}
9576
9577static inline void
9578tr_buffer_free(struct tr_buffer *buffer)
9579{
9580 if (buffer->buf) {
9581 SIZED_FREE_N(buffer->buf, buffer->capa);
9582 }
9583}
9584
9585struct tr_pair {
9586 VALUE search;
9587 VALUE replace;
9588};
9589
9591 struct tr_pair *pairs;
9592 size_t index;
9593 rb_encoding *enc;
9594 int cr;
9595};
9596
9597static int
9598tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9599{
9600 struct tr_trans_pairs_coerce_args *args = (struct tr_trans_pairs_coerce_args *)_args;
9601 struct tr_pair *pair = &args->pairs[args->index];
9602 args->index++;
9603
9604 VALUE search = (VALUE)key;
9605 VALUE replace = (VALUE)value;
9606 StringValue(search);
9607 StringValue(replace);
9608
9609 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9610 rb_raise(rb_eArgError, "keys must be of size 1"); // TODO: better error message
9611 }
9612
9613 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9614 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9615
9616 pair->search = search;
9617 pair->replace = replace;
9618 return ST_CONTINUE;
9619}
9620
9621#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9622
9624 const unsigned char *s;
9625 const unsigned char *send;
9626
9627#ifdef HAVE_SIMD
9628 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9629 unsigned int needles_count;
9630#ifdef HAVE_SIMD_NEON
9631 uint64_t matches_bitmap;
9632#endif
9633#ifdef HAVE_SIMD_SSE2
9634 int matches_bitmap;
9635#endif
9636#endif
9637
9638 VALUE trans_table[256];
9639};
9640
9641static inline VALUE
9642tr_trans_pairs_search_basic(struct tr_trans_pairs_search *search)
9643{
9644 while (search->s < search->send) {
9645 VALUE repl = search->trans_table[*search->s];
9646 if (UNLIKELY(repl)) {
9647 return repl;
9648 }
9649
9650 search->s++;
9651 }
9652
9653 return 0;
9654}
9655
9656#ifdef HAVE_SIMD_SSE2
9657static inline VALUE
9658tr_trans_pairs_next_match_sse2(struct tr_trans_pairs_search *search)
9659{
9660 RUBY_ASSERT(search->matches_bitmap > 0);
9661 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9662
9663 RUBY_ASSERT(trailing_zeros < (sizeof(search->matches_bitmap) * CHAR_BIT));
9664 search->matches_bitmap >>= trailing_zeros;
9665 search->s += trailing_zeros;
9666
9667 RUBY_ASSERT(search->s <= search->send);
9668 return search->trans_table[*search->s];
9669}
9670
9671static inline VALUE
9672tr_trans_pairs_search_sse2(struct tr_trans_pairs_search *search)
9673{
9674 const unsigned int needles_count = search->needles_count;
9675 if (needles_count) {
9676 RBIMPL_ASSERT_OR_ASSUME(needles_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9677
9678 if (search->matches_bitmap) {
9679 return tr_trans_pairs_next_match_sse2(search);
9680 }
9681
9682 if ((size_t)(search->send - search->s) >= sizeof(__m128i)) {
9683 unsigned int i;
9684 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9685 for (i = 0; i < needles_count; i++) {
9686 masks[i] = _mm_set1_epi8(search->needles[i]);
9687 }
9688
9689 do {
9690 const __m128i bytes = _mm_loadu_si128((__m128i const *)search->s);
9691
9692 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9693 for (i = 0; i < needles_count; i++) {
9694 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9695 }
9696
9697 for (i = 1; i < needles_count; i++) {
9698 matches[0] = _mm_or_si128(matches[0], matches[i]);
9699 }
9700
9701 const int bitmap = _mm_movemask_epi8(matches[0]);
9702
9703 if (bitmap) {
9704 search->matches_bitmap = bitmap;
9705 return tr_trans_pairs_next_match_sse2(search);
9706 }
9707 search->s += sizeof(__m128i);
9708 } while ((size_t)(search->send - search->s) >= sizeof(__m128i));
9709 }
9710 }
9711 return tr_trans_pairs_search_basic(search);
9712}
9713
9714#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9715#endif
9716
9717#ifdef HAVE_SIMD_NEON
9718static inline VALUE
9719tr_trans_pairs_next_match_neon(struct tr_trans_pairs_search *search)
9720{
9721 RUBY_ASSERT(search->matches_bitmap > 0);
9722 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9723
9724 // uint64_t >>= 64 would be undefined behaviour
9725 RUBY_ASSERT(trailing_zeros < (sizeof(search->matches_bitmap) * CHAR_BIT));
9726 search->matches_bitmap >>= trailing_zeros;
9727 search->s += trailing_zeros / 4;
9728
9729 RUBY_ASSERT(search->s <= search->send);
9730 return search->trans_table[*search->s];
9731}
9732
9733static inline VALUE
9734tr_trans_pairs_search_neon(struct tr_trans_pairs_search *search)
9735{
9736 const unsigned int needles_count = search->needles_count;
9737 if (needles_count) {
9738 RBIMPL_ASSERT_OR_ASSUME(needles_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9739
9740 if (search->matches_bitmap) {
9741 return tr_trans_pairs_next_match_neon(search);
9742 }
9743
9744 if ((size_t)(search->send - search->s) >= sizeof(uint8x16_t)) {
9745 unsigned int i;
9746 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9747 for (i = 0; i < needles_count; i++) {
9748 masks[i] = vdupq_n_u8(search->needles[i]);
9749 }
9750
9751 do {
9752 const uint8x16_t bytes = vld1q_u8(search->s);
9753
9754 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9755 for (i = 0; i < needles_count; i++) {
9756 matches[i] = vceqq_u8(bytes, masks[i]);
9757 }
9758
9759 for (i = 1; i < needles_count; i++) {
9760 matches[0] = vorrq_u8(matches[0], matches[i]);
9761 }
9762
9763 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9764 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9765
9766 if (bitmap) {
9767 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9768 return tr_trans_pairs_next_match_neon(search);
9769 }
9770 search->s += sizeof(uint8x16_t);
9771 } while ((size_t)(search->send - search->s) >= sizeof(uint8x16_t));
9772 }
9773 }
9774 return tr_trans_pairs_search_basic(search);
9775}
9776
9777#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9778#endif
9779
9780#ifndef tr_trans_pairs_search_impl
9781#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9782#endif
9783
9784static inline void
9785tr_trans_pairs_consume_match(struct tr_trans_pairs_search *search)
9786{
9787 search->s++;
9788#ifdef HAVE_SIMD
9789 search->matches_bitmap >>= 1;
9790#endif
9791}
9792
9793static VALUE
9794tr_trans_pairs(VALUE str, VALUE pairs_val)
9795{
9796 Check_Type(pairs_val, T_HASH);
9797 size_t pairs_count = RHASH_SIZE(pairs_val);
9798 mustnot_broken(str);
9799 rb_str_modify(str);
9800
9801 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0) return Qnil;
9802
9803 VALUE pairs_handle;
9804 struct tr_pair *pairs = ALLOCV_N(struct tr_pair, pairs_handle, pairs_count);
9805
9806 int cr = rb_enc_str_coderange(str);
9807 rb_encoding *enc = rb_str_enc_get(str);
9808
9809 struct tr_trans_pairs_coerce_args coerce_args = {
9810 .pairs = pairs,
9811 .enc = enc,
9812 .cr = cr,
9813 };
9814 rb_hash_foreach(pairs_val, tr_trans_pairs_coerce_i, (VALUE)&coerce_args);
9815 rb_encoding *e1 = coerce_args.enc;
9816
9817 /* Keys could be deleted from pairs_val during rb_hash_foreach when coercing
9818 * the keys/values, so we need to update pairs_count to the number of pairs we
9819 * were actually able to extract from pairs_val. */
9820 pairs_count = coerce_args.index;
9821
9822 VALUE hash = 0;
9823
9824 const unsigned char *sstart = (unsigned char *)RSTRING_PTR(str);
9825 rb_len_t str_len = RSTRING_LEN(str);
9826 int termlen = rb_enc_mbminlen(e1);
9827
9828 struct tr_buffer buffer;
9829 tr_buffer_init(&buffer, str_len);
9830 bool modify = false;
9831
9832 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9833
9834 struct tr_trans_pairs_search search = {
9835 .s = sstart,
9836 .send = sstart + str_len,
9837 };
9838
9839 for (size_t index = 0; index < pairs_count; index++) {
9840 struct tr_pair *pair = &pairs[index];
9841
9842 char *ptr = RSTRING_PTR(pair->search);
9843 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr, RSTRING_END(pair->search), e1);
9844
9845 const unsigned char first_byte = (unsigned char)*ptr;
9846
9847#ifdef HAVE_SIMD
9848 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9849 search.needles[index] = first_byte;
9850 search.needles_count++;
9851 }
9852#endif
9853
9854 if (rb_enc_codelen(codepoint, e1) == 1) {
9855 search.trans_table[first_byte] = pair->replace;
9856 }
9857 else {
9858 search.trans_table[first_byte] = Qundef;
9859 if (!hash) {
9860 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9861 }
9862 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9863 }
9864 }
9865
9866 const unsigned char *checkpoint = search.s;
9867 VALUE repl;
9868 while ((repl = tr_trans_pairs_search_impl(&search))) {
9869 int clen = 1;
9870
9871 if (UNLIKELY(repl == Qundef)) {
9872 unsigned int c = rb_enc_mbc_to_codepoint((char *)search.s, (char *)search.send, e1);
9873 clen = rb_enc_codelen(c, e1);
9874 repl = rb_hash_lookup2(hash, UINT2NUM(c), 0);
9875 if (!repl) {
9876 tr_trans_pairs_consume_match(&search);
9877 continue;
9878 }
9879 }
9881
9882 modify = true;
9883
9884 if (checkpoint < search.s) {
9885 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9886 }
9887 tr_buffer_append_str(&buffer, repl);
9888 checkpoint = search.s + clen;
9889 tr_trans_pairs_consume_match(&search);
9890
9891 if (cr == ENC_CODERANGE_7BIT && rb_enc_str_coderange(repl) != ENC_CODERANGE_7BIT) {
9893 }
9894 }
9895
9896 if (modify && checkpoint < search.s) {
9897 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9898 }
9899 }
9900 else {
9901 const unsigned char *s = sstart;
9902 const unsigned char *send = sstart + str_len;
9903
9904 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9905
9906 for (size_t index = 0; index < pairs_count; index++) {
9907 struct tr_pair *pair = &pairs[index];
9908
9909 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search), RSTRING_END(pair->search), e1);
9910 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9911 }
9912
9913 while (s < send) {
9914 bool may_modify = false;
9915
9916 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9917 if (!MBCLEN_CHARFOUND_P(r)) {
9918 tr_buffer_free(&buffer);
9919 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9920 }
9921 int clen = MBCLEN_CHARFOUND_LEN(r);
9922 unsigned int c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9923 unsigned int c0 = c;
9924
9925 rb_len_t tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
9926
9927 VALUE replacement = rb_hash_lookup(hash, UINT2NUM(c));
9928 if (NIL_P(replacement)) {
9929 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9930 c = c0;
9931 if (enc != e1) may_modify = true;
9932 }
9933 else {
9934 tlen = RSTRING_LEN(replacement);
9935 modify = true;
9936 }
9937
9938 if (NIL_P(replacement)) {
9939 tr_buffer_mbcput(&buffer, c, enc);
9940 }
9941 else {
9942 tr_buffer_append_str(&buffer, replacement);
9943 }
9944
9945 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
9946 modify = true;
9947 }
9948
9949 if (cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) {
9951 }
9952
9953 s += clen;
9954 }
9955 }
9956
9957 ALLOCV_END(pairs_handle);
9958
9959 if (!modify) {
9960 return Qnil;
9961 }
9962
9963 if (!STR_EMBED_P(str)) {
9964 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9965 }
9966 tr_buffer_ensure_capa(&buffer, termlen);
9967 TERM_FILL((char *)buffer.ptr, termlen);
9968 RSTRING(str)->as.heap.ptr = (char *)buffer.buf;
9969 STR_SET_LEN(str, buffer.ptr - buffer.buf);
9970 STR_SET_NOEMBED(str);
9971 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
9972
9973 RB_GC_GUARD(hash);
9974
9975 if (cr != ENC_CODERANGE_BROKEN)
9976 ENC_CODERANGE_SET(str, cr);
9977 rb_enc_associate(str, e1);
9978 return str;
9979}
9980
9981/*
9982 * call-seq:
9983 * tr!(selector, replacements) -> self or nil
9984 * tr!(pairs) -> self or nil
9985 *
9986 * Like String#tr, except:
9987 *
9988 * - Performs substitutions in +self+ (not in a copy of +self+).
9989 * - Returns +self+ if any modifications were made, +nil+ otherwise.
9990 *
9991 * Related: {Modifying}[rdoc-ref:String@Modifying].
9992 */
9993
9994static VALUE
9995rb_str_tr_bang(int argc, VALUE *argv, VALUE str)
9996{
9997 rb_check_arity(argc, 1, 2);
9998
9999 if (argc == 1) {
10000 VALUE pairs = argv[0];
10001 return tr_trans_pairs(str, pairs);
10002 }
10003
10004 VALUE src = argv[0], repl = argv[1];
10005 return tr_trans(str, src, repl, 0);
10006}
10007
10008
10009/*
10010 * call-seq:
10011 * tr(selector, replacements) -> new_string
10012 * tr(pairs) -> new_string
10013 *
10014 * Accepts either a +selector+ and a +replacements+ string,
10015 * or a single +pairs+ Hash.
10016 *
10017 * When a +pairs+ Hash is provided the keys, returns a copy of +self+ with
10018 * the keys of the hash replaced by the values.
10019 *
10020 * - They keys must be strings containing a single codepoints.
10021 * - The values can be of any length.
10022 *
10023 * Example:
10024 *
10025 * 'hello'.tr('e' => 'er', 'l' => '', 'o' => 'o !') #=> "hero !"
10026 *
10027 * When +selector+ and +replacements+are provided, returns a copy of +self+
10028 * with each character specified by string +selector+ translated to the
10029 * corresponding character in string +replacements+.
10030 * The correspondence is _positional_:
10031 *
10032 * - Each occurrence of the first character specified by +selector+
10033 * is translated to the first character in +replacements+.
10034 * - Each occurrence of the second character specified by +selector+
10035 * is translated to the second character in +replacements+.
10036 * - And so on.
10037 *
10038 * Example:
10039 *
10040 * 'hello'.tr('el', 'ip') #=> "hippo"
10041 *
10042 * If +replacements+ is shorter than +selector+,
10043 * it is implicitly padded with its own last character:
10044 *
10045 * 'hello'.tr('aeiou', '-') # => "h-ll-"
10046 * 'hello'.tr('aeiou', 'AA-') # => "hAll-"
10047 *
10048 * Arguments +selector+ and +replacements+ must be valid character selectors
10049 * (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
10050 * and may use any of its valid forms, including negation, ranges, and escapes:
10051 *
10052 * 'hello'.tr('^aeiou', '-') # => "-e--o" # Negation.
10053 * 'ibm'.tr('b-z', 'a-z') # => "hal" # Range.
10054 * 'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret.
10055 * 'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen.
10056 * 'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash.
10057 *
10058 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10059 */
10060
10061static VALUE
10062rb_str_tr(int argc, VALUE *argv, VALUE str)
10063{
10064 rb_check_arity(argc, 1, 2);
10065
10066 str = str_duplicate(rb_cString, str);
10067
10068 if (argc == 1) {
10069 VALUE pairs = argv[0];
10070 VALUE result = tr_trans_pairs(str, pairs);
10071 if (NIL_P(result)) result = str;
10072 return str;
10073 }
10074
10075 VALUE src = argv[0], repl = argv[1];
10076 tr_trans(str, src, repl, 0);
10077 return str;
10078}
10079
10080#define TR_TABLE_MAX (UCHAR_MAX+1)
10081#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10082static void
10083tr_setup_table(VALUE str, char stable[TR_TABLE_SIZE], int first,
10084 VALUE *tablep, VALUE *ctablep, rb_encoding *enc)
10085{
10086 const unsigned int errc = -1;
10087 char buf[TR_TABLE_MAX];
10088 struct tr tr;
10089 unsigned int c;
10090 VALUE table = 0, ptable = 0;
10091 int i, l, cflag = 0;
10092
10093 tr.p = RSTRING_PTR(str); tr.pend = tr.p + RSTRING_LEN(str);
10094 tr.gen = tr.now = tr.max = 0;
10095
10096 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(tr.p, tr.pend, &l, enc) == '^') {
10097 cflag = 1;
10098 tr.p += l;
10099 }
10100 if (first) {
10101 for (i=0; i<TR_TABLE_MAX; i++) {
10102 stable[i] = 1;
10103 }
10104 stable[TR_TABLE_MAX] = cflag;
10105 }
10106 else if (stable[TR_TABLE_MAX] && !cflag) {
10107 stable[TR_TABLE_MAX] = 0;
10108 }
10109 for (i=0; i<TR_TABLE_MAX; i++) {
10110 buf[i] = cflag;
10111 }
10112
10113 while ((c = trnext(&tr, enc)) != errc) {
10114 if (c < TR_TABLE_MAX) {
10115 buf[(unsigned char)c] = !cflag;
10116 }
10117 else {
10118 VALUE key = UINT2NUM(c);
10119
10120 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10121 if (cflag) {
10122 ptable = *ctablep;
10123 table = ptable ? ptable : rb_hash_new();
10124 *ctablep = table;
10125 }
10126 else {
10127 table = rb_hash_new();
10128 ptable = *tablep;
10129 *tablep = table;
10130 }
10131 }
10132 if (table && (!ptable || (cflag ^ !NIL_P(rb_hash_aref(ptable, key))))) {
10133 rb_hash_aset(table, key, Qtrue);
10134 }
10135 }
10136 }
10137 for (i=0; i<TR_TABLE_MAX; i++) {
10138 stable[i] = stable[i] && buf[i];
10139 }
10140 if (!table && !cflag) {
10141 *tablep = 0;
10142 }
10143}
10144
10145
10146static int
10147tr_find(unsigned int c, const char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
10148{
10149 if (c < TR_TABLE_MAX) {
10150 return table[c] != 0;
10151 }
10152 else {
10153 VALUE v = UINT2NUM(c);
10154
10155 if (del) {
10156 if (!NIL_P(rb_hash_lookup(del, v)) &&
10157 (!nodel || NIL_P(rb_hash_lookup(nodel, v)))) {
10158 return TRUE;
10159 }
10160 }
10161 else if (nodel && !NIL_P(rb_hash_lookup(nodel, v))) {
10162 return FALSE;
10163 }
10164 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10165 }
10166}
10167
10168/*
10169 * call-seq:
10170 * delete!(*selectors) -> self or nil
10171 *
10172 * Like String#delete, but modifies +self+ in place;
10173 * returns +self+ if any characters were deleted, +nil+ otherwise.
10174 *
10175 * Related: see {Modifying}[rdoc-ref:String@Modifying].
10176 */
10177
10178static VALUE
10179rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
10180{
10181 char squeez[TR_TABLE_SIZE];
10182 rb_encoding *enc = 0;
10183 char *s, *send, *t;
10184 VALUE del = 0, nodel = 0;
10185 int modify = 0;
10186 int i, ascompat, cr;
10187
10188 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
10190 for (i=0; i<argc; i++) {
10191 VALUE s = argv[i];
10192
10193 StringValue(s);
10194 enc = rb_enc_check(str, s);
10195 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10196 }
10197
10198 str_modify_keep_cr(str);
10199 ascompat = rb_enc_asciicompat(enc);
10200 s = t = RSTRING_PTR(str);
10201 send = RSTRING_END(str);
10202 cr = ascompat ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
10203 while (s < send) {
10204 unsigned int c;
10205 int clen;
10206
10207 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
10208 if (squeez[c]) {
10209 modify = 1;
10210 }
10211 else {
10212 if (t != s) *t = c;
10213 t++;
10214 }
10215 s++;
10216 }
10217 else {
10218 c = rb_enc_codepoint_len(s, send, &clen, enc);
10219
10220 if (tr_find(c, squeez, del, nodel)) {
10221 modify = 1;
10222 }
10223 else {
10224 if (t != s) rb_enc_mbcput(c, t, enc);
10225 t += clen;
10227 }
10228 s += clen;
10229 }
10230 }
10231 TERM_FILL(t, TERM_LEN(str));
10232 STR_SET_LEN(str, t - RSTRING_PTR(str));
10233 ENC_CODERANGE_SET(str, cr);
10234
10235 if (modify) return str;
10236 return Qnil;
10237}
10238
10239
10240/*
10241 * call-seq:
10242 * delete(*selectors) -> new_string
10243 *
10244 * :include: doc/string/delete.rdoc
10245 *
10246 */
10247
10248static VALUE
10249rb_str_delete(int argc, VALUE *argv, VALUE str)
10250{
10251 str = str_duplicate(rb_cString, str);
10252 rb_str_delete_bang(argc, argv, str);
10253 return str;
10254}
10255
10256
10257/*
10258 * call-seq:
10259 * squeeze!(*selectors) -> self or nil
10260 *
10261 * Like String#squeeze, except that:
10262 *
10263 * - Characters are squeezed in +self+ (not in a copy of +self+).
10264 * - Returns +self+ if any changes are made, +nil+ otherwise.
10265 *
10266 * Related: See {Modifying}[rdoc-ref:String@Modifying].
10267 */
10268
10269static VALUE
10270rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
10271{
10272 char squeez[TR_TABLE_SIZE];
10273 rb_encoding *enc = 0;
10274 VALUE del = 0, nodel = 0;
10275 unsigned char *s, *send, *t;
10276 int i, modify = 0;
10277 int ascompat, singlebyte = single_byte_optimizable(str);
10278 unsigned int save;
10279
10280 if (argc == 0) {
10281 enc = STR_ENC_GET(str);
10282 }
10283 else {
10284 for (i=0; i<argc; i++) {
10285 VALUE s = argv[i];
10286
10287 StringValue(s);
10288 enc = rb_enc_check(str, s);
10289 if (singlebyte && !single_byte_optimizable(s))
10290 singlebyte = 0;
10291 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10292 }
10293 }
10294
10295 str_modify_keep_cr(str);
10296 s = t = (unsigned char *)RSTRING_PTR(str);
10297 if (!s || RSTRING_LEN(str) == 0) return Qnil;
10298 send = (unsigned char *)RSTRING_END(str);
10299 save = -1;
10300 ascompat = rb_enc_asciicompat(enc);
10301
10302 if (singlebyte) {
10303 while (s < send) {
10304 unsigned int c = *s++;
10305 if (c != save || (argc > 0 && !squeez[c])) {
10306 *t++ = save = c;
10307 }
10308 }
10309 }
10310 else {
10311 while (s < send) {
10312 unsigned int c;
10313 int clen;
10314
10315 if (ascompat && (c = *s) < 0x80) {
10316 if (c != save || (argc > 0 && !squeez[c])) {
10317 *t++ = save = c;
10318 }
10319 s++;
10320 }
10321 else {
10322 c = rb_enc_codepoint_len((char *)s, (char *)send, &clen, enc);
10323
10324 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10325 if (t != s) rb_enc_mbcput(c, t, enc);
10326 save = c;
10327 t += clen;
10328 }
10329 s += clen;
10330 }
10331 }
10332 }
10333
10334 TERM_FILL((char *)t, TERM_LEN(str));
10335 if ((char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10336 STR_SET_LEN(str, (char *)t - RSTRING_PTR(str));
10337 modify = 1;
10338 }
10339
10340 if (modify) return str;
10341 return Qnil;
10342}
10343
10344
10345/*
10346 * call-seq:
10347 * squeeze(*selectors) -> new_string
10348 *
10349 * :include: doc/string/squeeze.rdoc
10350 *
10351 */
10352
10353static VALUE
10354rb_str_squeeze(int argc, VALUE *argv, VALUE str)
10355{
10356 str = str_duplicate(rb_cString, str);
10357 rb_str_squeeze_bang(argc, argv, str);
10358 return str;
10359}
10360
10361
10362/*
10363 * call-seq:
10364 * tr_s!(selector, replacements) -> self or nil
10365 *
10366 * Like String#tr_s, except:
10367 *
10368 * - Modifies +self+ in place (not a copy of +self+).
10369 * - Returns +self+ if any changes were made, +nil+ otherwise.
10370 *
10371 * Related: {Modifying}[rdoc-ref:String@Modifying].
10372 */
10373
10374static VALUE
10375rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
10376{
10377 return tr_trans(str, src, repl, 1);
10378}
10379
10380
10381/*
10382 * call-seq:
10383 * tr_s(selector, replacements) -> new_string
10384 *
10385 * Like String#tr, except:
10386 *
10387 * - Also squeezes the modified portions of the translated string;
10388 * see String#squeeze.
10389 * - Returns the translated and squeezed string.
10390 *
10391 * Examples:
10392 *
10393 * 'hello'.tr_s('l', 'r') #=> "hero"
10394 * 'hello'.tr_s('el', '-') #=> "h-o"
10395 * 'hello'.tr_s('el', 'hx') #=> "hhxo"
10396 *
10397 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10398 *
10399 */
10400
10401static VALUE
10402rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
10403{
10404 str = str_duplicate(rb_cString, str);
10405 tr_trans(str, src, repl, 1);
10406 return str;
10407}
10408
10409
10410/*
10411 * call-seq:
10412 * count(*selectors) -> integer
10413 *
10414 * :include: doc/string/count.rdoc
10415 */
10416
10417static VALUE
10418rb_str_count(int argc, VALUE *argv, VALUE str)
10419{
10420 char table[TR_TABLE_SIZE];
10421 rb_encoding *enc = 0;
10422 VALUE del = 0, nodel = 0, tstr;
10423 const char *s, *send;
10424 int i;
10425 int ascompat;
10426 size_t n = 0;
10427
10429
10430 tstr = argv[0];
10431 StringValue(tstr);
10432 enc = rb_enc_check(str, tstr);
10433 if (argc == 1) {
10434 const char *ptstr;
10435 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10436 (ptstr = RSTRING_PTR(tstr),
10437 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
10438 !is_broken_string(str)) {
10439 int clen;
10440 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10441
10442 s = RSTRING_PTR(str);
10443 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10444 send = RSTRING_END(str);
10445 while (s < send) {
10446 if (*(unsigned char*)s++ == c) n++;
10447 }
10448 return SIZET2NUM(n);
10449 }
10450 }
10451
10452 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10453 for (i=1; i<argc; i++) {
10454 tstr = argv[i];
10455 StringValue(tstr);
10456 enc = rb_enc_check(str, tstr);
10457 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10458 }
10459
10460 s = RSTRING_PTR(str);
10461 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10462 send = RSTRING_END(str);
10463 ascompat = rb_enc_asciicompat(enc);
10464 while (s < send) {
10465 unsigned int c;
10466
10467 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
10468 if (table[c]) {
10469 n++;
10470 }
10471 s++;
10472 }
10473 else {
10474 int clen;
10475 c = rb_enc_codepoint_len(s, send, &clen, enc);
10476 if (tr_find(c, table, del, nodel)) {
10477 n++;
10478 }
10479 s += clen;
10480 }
10481 }
10482
10483 return SIZET2NUM(n);
10484}
10485
10486static VALUE
10487rb_fs_check(VALUE val)
10488{
10489 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING) && !RB_TYPE_P(val, T_REGEXP)) {
10490 val = rb_check_string_type(val);
10491 if (NIL_P(val)) return 0;
10492 }
10493 return val;
10494}
10495
10496static const char isspacetable[256] = {
10497 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10499 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10500 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10502 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10504 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10505 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10506 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10513};
10514
10515#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10516
10517static rb_len_t
10518split_string(VALUE result, VALUE str, rb_len_t beg, rb_len_t len, rb_len_t empty_count)
10519{
10520 if (empty_count >= 0 && len == 0) {
10521 return empty_count + 1;
10522 }
10523 if (empty_count > 0) {
10524 /* make different substrings */
10525 if (result) {
10526 do {
10527 rb_ary_push(result, str_new_empty_String(str));
10528 } while (--empty_count > 0);
10529 }
10530 else {
10531 do {
10532 rb_yield(str_new_empty_String(str));
10533 } while (--empty_count > 0);
10534 }
10535 }
10536 str = rb_str_subseq(str, beg, len);
10537 if (result) {
10538 rb_ary_push(result, str);
10539 }
10540 else {
10541 rb_yield(str);
10542 }
10543 return empty_count;
10544}
10545
10546typedef enum {
10547 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10548} split_type_t;
10549
10550static split_type_t
10551literal_split_pattern(VALUE spat, split_type_t default_type)
10552{
10553 rb_encoding *enc = STR_ENC_GET(spat);
10554 const char *ptr;
10555 rb_len_t len;
10556 RSTRING_GETMEM(spat, ptr, len);
10557 if (len == 0) {
10558 /* Special case - split into chars */
10559 return SPLIT_TYPE_CHARS;
10560 }
10561 else if (rb_enc_asciicompat(enc)) {
10562 if (len == 1 && ptr[0] == ' ') {
10563 return SPLIT_TYPE_AWK;
10564 }
10565 }
10566 else {
10567 int l;
10568 if (rb_enc_ascget(ptr, ptr + len, &l, enc) == ' ' && len == l) {
10569 return SPLIT_TYPE_AWK;
10570 }
10571 }
10572 return default_type;
10573}
10574
10575/*
10576 * call-seq:
10577 * split(field_sep = $;, limit = 0) -> array_of_substrings
10578 * split(field_sep = $;, limit = 0) {|substring| ... } -> self
10579 *
10580 * :include: doc/string/split.rdoc
10581 *
10582 */
10583
10584static VALUE
10585rb_str_split_m(int argc, VALUE *argv, VALUE str)
10586{
10587 rb_encoding *enc;
10588 VALUE spat;
10589 VALUE limit;
10590 split_type_t split_type;
10591 rb_len_t beg, end, i = 0, empty_count = -1;
10592 int lim = 0;
10593 VALUE result, tmp;
10594
10595 result = rb_block_given_p() ? Qfalse : Qnil;
10596 if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
10597 lim = NUM2INT(limit);
10598 if (lim <= 0) limit = Qnil;
10599 else if (lim == 1) {
10600 if (RSTRING_LEN(str) == 0)
10601 return result ? rb_ary_new2(0) : str;
10602 tmp = str_duplicate(rb_cString, str);
10603 if (!result) {
10604 rb_yield(tmp);
10605 return str;
10606 }
10607 return rb_ary_new3(1, tmp);
10608 }
10609 i = 1;
10610 }
10611 if (NIL_P(limit) && !lim) empty_count = 0;
10612
10613 enc = STR_ENC_GET(str);
10614 split_type = SPLIT_TYPE_REGEXP;
10615 if (!NIL_P(spat)) {
10616 spat = get_pat_quoted(spat, 0);
10617 }
10618 else if (NIL_P(spat = rb_fs)) {
10619 split_type = SPLIT_TYPE_AWK;
10620 }
10621 else if (!(spat = rb_fs_check(spat))) {
10622 rb_raise(rb_eTypeError, "value of $; must be String or Regexp");
10623 }
10624 else {
10625 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$; is set to non-nil value");
10626 }
10627 if (split_type != SPLIT_TYPE_AWK) {
10628 switch (BUILTIN_TYPE(spat)) {
10629 case T_REGEXP:
10630 rb_reg_options(spat); /* check if uninitialized */
10631 tmp = RREGEXP_SRC(spat);
10632 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10633 if (split_type == SPLIT_TYPE_AWK) {
10634 spat = tmp;
10635 split_type = SPLIT_TYPE_STRING;
10636 }
10637 break;
10638
10639 case T_STRING:
10640 mustnot_broken(spat);
10641 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10642 break;
10643
10644 default:
10646 }
10647 }
10648
10649#define SPLIT_STR(beg, len) ( \
10650 empty_count = split_string(result, str, beg, len, empty_count), \
10651 str_mod_check(str, str_start, str_len))
10652
10653 beg = 0;
10654 const char *ptr = RSTRING_PTR(str);
10655 const char *const str_start = ptr;
10656 const rb_len_t str_len = RSTRING_LEN(str);
10657 const char *const eptr = str_start + str_len;
10658 if (split_type == SPLIT_TYPE_AWK) {
10659 const char *bptr = ptr;
10660 int skip = 1;
10661 unsigned int c;
10662
10663 if (result) result = rb_ary_new();
10664 end = beg;
10665 if (is_ascii_string(str)) {
10666 while (ptr < eptr) {
10667 c = (unsigned char)*ptr++;
10668 if (skip) {
10669 if (ascii_isspace(c)) {
10670 beg = ptr - bptr;
10671 }
10672 else {
10673 end = ptr - bptr;
10674 skip = 0;
10675 if (!NIL_P(limit) && lim <= i) break;
10676 }
10677 }
10678 else if (ascii_isspace(c)) {
10679 SPLIT_STR(beg, end-beg);
10680 skip = 1;
10681 beg = ptr - bptr;
10682 if (!NIL_P(limit)) ++i;
10683 }
10684 else {
10685 end = ptr - bptr;
10686 }
10687 }
10688 }
10689 else {
10690 while (ptr < eptr) {
10691 int n;
10692
10693 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10694 ptr += n;
10695 if (skip) {
10696 if (rb_isspace(c)) {
10697 beg = ptr - bptr;
10698 }
10699 else {
10700 end = ptr - bptr;
10701 skip = 0;
10702 if (!NIL_P(limit) && lim <= i) break;
10703 }
10704 }
10705 else if (rb_isspace(c)) {
10706 SPLIT_STR(beg, end-beg);
10707 skip = 1;
10708 beg = ptr - bptr;
10709 if (!NIL_P(limit)) ++i;
10710 }
10711 else {
10712 end = ptr - bptr;
10713 }
10714 }
10715 }
10716 }
10717 else if (split_type == SPLIT_TYPE_STRING) {
10718 const char *substr_start = ptr;
10719 const char *sptr = RSTRING_PTR(spat);
10720 rb_len_t slen = RSTRING_LEN(spat);
10721
10722 if (result) result = rb_ary_new();
10723 mustnot_broken(str);
10724 enc = rb_enc_check(str, spat);
10725 while (ptr < eptr &&
10726 (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10727 /* Check we are at the start of a char */
10728 const char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc);
10729 if (t != ptr + end) {
10730 ptr = t;
10731 continue;
10732 }
10733 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10734 str_mod_check(spat, sptr, slen);
10735 ptr += end + slen;
10736 substr_start = ptr;
10737 if (!NIL_P(limit) && lim <= ++i) break;
10738 }
10739 beg = ptr - str_start;
10740 }
10741 else if (split_type == SPLIT_TYPE_CHARS) {
10742 int n;
10743
10744 if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
10745 mustnot_broken(str);
10746 enc = rb_enc_get(str);
10747 while (ptr < eptr &&
10748 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10749 SPLIT_STR(ptr - str_start, n);
10750 ptr += n;
10751 if (!NIL_P(limit) && lim <= ++i) break;
10752 }
10753 beg = ptr - str_start;
10754 }
10755 else {
10756 if (result) result = rb_ary_new();
10757 rb_len_t len = RSTRING_LEN(str);
10758 rb_len_t start = beg;
10759 int idx;
10760 int last_null = 0;
10761 VALUE match = 0;
10762
10763 for (; rb_reg_search(spat, str, start, 0) >= 0;
10764 (match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
10765 match = rb_backref_get();
10766 if (!result) rb_match_busy(match);
10767 end = RMATCH_BEG(match, 0);
10768 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10769 if (!ptr) {
10770 SPLIT_STR(0, 0);
10771 break;
10772 }
10773 else if (last_null == 1) {
10774 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10775 beg = start;
10776 }
10777 else {
10778 if (start == len)
10779 start++;
10780 else
10781 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10782 last_null = 1;
10783 continue;
10784 }
10785 }
10786 else {
10787 SPLIT_STR(beg, end-beg);
10788 beg = start = RMATCH_END(match, 0);
10789 }
10790 last_null = 0;
10791
10792 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10793 if (RMATCH_BEG(match, idx) == -1) continue;
10794 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10795 }
10796 if (!NIL_P(limit) && lim <= ++i) break;
10797 }
10798 if (match) rb_match_unbusy(match);
10799 }
10800 if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10801 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10802 }
10803
10804 return result ? result : str;
10805}
10806
10807VALUE
10808rb_str_split(VALUE str, const char *sep0)
10809{
10810 VALUE sep;
10811
10812 StringValue(str);
10813 sep = rb_str_new_cstr(sep0);
10814 return rb_str_split_m(1, &sep, str);
10815}
10816
10817#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10818
10819static inline int
10820enumerator_element(VALUE ary, VALUE e)
10821{
10822 if (ary) {
10823 rb_ary_push(ary, e);
10824 return 0;
10825 }
10826 else {
10827 rb_yield(e);
10828 return 1;
10829 }
10830}
10831
10832#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10833
10834static const char *
10835chomp_newline(const char *p, const char *e, rb_encoding *enc)
10836{
10837 const char *prev = rb_enc_prev_char(p, e, e, enc);
10838 if (rb_enc_is_newline(prev, e, enc)) {
10839 e = prev;
10840 prev = rb_enc_prev_char(p, e, e, enc);
10841 if (prev && rb_enc_ascget(prev, e, NULL, enc) == '\r')
10842 e = prev;
10843 }
10844 return e;
10845}
10846
10847static VALUE
10848get_rs(void)
10849{
10850 VALUE rs = rb_rs;
10851 if (!NIL_P(rs) &&
10852 (!RB_TYPE_P(rs, T_STRING) ||
10853 RSTRING_LEN(rs) != 1 ||
10854 RSTRING_PTR(rs)[0] != '\n')) {
10855 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$/ is set to non-default value");
10856 }
10857 return rs;
10858}
10859
10860#define rb_rs get_rs()
10861
10862static VALUE
10863rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
10864{
10865 rb_encoding *enc;
10866 VALUE line, rs, orig = str, opts = Qnil, chomp = Qfalse;
10867 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10868 rb_len_t pos, rslen;
10869 int rsnewline = 0;
10870
10871 if (rb_scan_args(argc, argv, "01:", &rs, &opts) == 0)
10872 rs = rb_rs;
10873 if (!NIL_P(opts)) {
10874 static ID keywords[1];
10875 if (!keywords[0]) {
10876 keywords[0] = rb_intern_const("chomp");
10877 }
10878 rb_get_kwargs(opts, keywords, 0, 1, &chomp);
10879 chomp = (!UNDEF_P(chomp) && RTEST(chomp));
10880 }
10881
10882 if (NIL_P(rs)) {
10883 if (!ENUM_ELEM(ary, str)) {
10884 return ary;
10885 }
10886 else {
10887 return orig;
10888 }
10889 }
10890
10891 if (!RSTRING_LEN(str)) goto end;
10892 str = rb_str_new_frozen(str);
10893 const char *const ptr = subptr = RSTRING_PTR(str);
10894 const rb_len_t len = RSTRING_LEN(str);
10895 pend = RSTRING_END(str);
10896 StringValue(rs);
10897 rslen = RSTRING_LEN(rs);
10898
10899 if (rs == rb_default_rs)
10900 enc = rb_enc_get(str);
10901 else
10902 enc = rb_enc_check(str, rs);
10903
10904 if (rslen == 0) {
10905 /* paragraph mode */
10906 int n;
10907 const char *eol = NULL;
10908 subend = subptr;
10909 while (subend < pend) {
10910 rb_len_t chomp_rslen = 0;
10911 do {
10912 if (rb_enc_ascget(subend, pend, &n, enc) != '\r')
10913 n = 0;
10914 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
10915 if (rb_enc_is_newline(subend + n, pend, enc)) {
10916 if (eol == subend) break;
10917 subend += rslen;
10918 if (subptr) {
10919 eol = subend;
10920 chomp_rslen = -rslen;
10921 }
10922 }
10923 else {
10924 if (!subptr) subptr = subend;
10925 subend += rslen;
10926 }
10927 rslen = 0;
10928 } while (subend < pend);
10929 if (!subptr) break;
10930 if (rslen == 0) chomp_rslen = 0;
10931 line = rb_str_subseq(str, subptr - ptr,
10932 subend - subptr + (chomp ? chomp_rslen : rslen));
10933 if (ENUM_ELEM(ary, line)) {
10934 str_mod_check(str, ptr, len);
10935 }
10936 subptr = eol = NULL;
10937 }
10938 goto end;
10939 }
10940 else {
10941 rsptr = RSTRING_PTR(rs);
10942 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
10943 rb_enc_is_newline(rsptr, rsptr + RSTRING_LEN(rs), enc)) {
10944 rsnewline = 1;
10945 }
10946 }
10947
10948 if ((rs == rb_default_rs) && !rb_enc_asciicompat(enc)) {
10949 rs = rb_str_new(rsptr, rslen);
10950 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
10951 rsptr = RSTRING_PTR(rs);
10952 rslen = RSTRING_LEN(rs);
10953 }
10954
10955 while (subptr < pend) {
10956 pos = rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
10957 if (pos < 0) break;
10958 hit = subptr + pos;
10959 adjusted = rb_enc_right_char_head(subptr, hit, pend, enc);
10960 if (hit != adjusted) {
10961 subptr = adjusted;
10962 continue;
10963 }
10964 subend = hit += rslen;
10965 if (chomp) {
10966 if (rsnewline) {
10967 subend = chomp_newline(subptr, subend, enc);
10968 }
10969 else {
10970 subend -= rslen;
10971 }
10972 }
10973 line = rb_str_subseq(str, subptr - ptr, subend - subptr);
10974 if (ENUM_ELEM(ary, line)) {
10975 str_mod_check(str, ptr, len);
10976 str_mod_check(rs, rsptr, rslen);
10977 }
10978 subptr = hit;
10979 }
10980
10981 if (subptr < pend) {
10982 if (chomp) {
10983 if (rsnewline) {
10984 pend = chomp_newline(subptr, pend, enc);
10985 }
10986 else if (pend - subptr >= rslen &&
10987 memcmp(pend - rslen, rsptr, rslen) == 0) {
10988 pend -= rslen;
10989 }
10990 }
10991 line = rb_str_subseq(str, subptr - ptr, pend - subptr);
10992 ENUM_ELEM(ary, line);
10993 RB_GC_GUARD(str);
10994 }
10995
10996 end:
10997 if (ary)
10998 return ary;
10999 else
11000 return orig;
11001}
11002
11003/*
11004 * call-seq:
11005 * each_line(record_separator = $/, chomp: false) {|substring| ... } -> self
11006 * each_line(record_separator = $/, chomp: false) -> enumerator
11007 *
11008 * :include: doc/string/each_line.rdoc
11009 *
11010 */
11011
11012static VALUE
11013rb_str_each_line(int argc, VALUE *argv, VALUE str)
11014{
11015 RETURN_SIZED_ENUMERATOR(str, argc, argv, 0);
11016 return rb_str_enumerate_lines(argc, argv, str, 0);
11017}
11018
11019/*
11020 * call-seq:
11021 * lines(record_separator = $/, chomp: false) -> array_of_strings
11022 *
11023 * Returns substrings ("lines") of +self+
11024 * according to the given arguments:
11025 *
11026 * s = <<~EOT
11027 * This is the first line.
11028 * This is line two.
11029 *
11030 * This is line four.
11031 * This is line five.
11032 * EOT
11033 *
11034 * With the default argument values:
11035 *
11036 * $/ # => "\n"
11037 * s.lines
11038 * # =>
11039 * ["This is the first line.\n",
11040 * "This is line two.\n",
11041 * "\n",
11042 * "This is line four.\n",
11043 * "This is line five.\n"]
11044 *
11045 * With a different +record_separator+:
11046 *
11047 * record_separator = ' is '
11048 * s.lines(record_separator)
11049 * # =>
11050 * ["This is ",
11051 * "the first line.\nThis is ",
11052 * "line two.\n\nThis is ",
11053 * "line four.\nThis is ",
11054 * "line five.\n"]
11055 *
11056 * With keyword argument +chomp+ as +true+,
11057 * removes the trailing newline from each line:
11058 *
11059 * s.lines(chomp: true)
11060 * # =>
11061 * ["This is the first line.",
11062 * "This is line two.",
11063 * "",
11064 * "This is line four.",
11065 * "This is line five."]
11066 *
11067 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
11068 */
11069
11070static VALUE
11071rb_str_lines(int argc, VALUE *argv, VALUE str)
11072{
11073 VALUE ary = WANTARRAY("lines", 0);
11074 return rb_str_enumerate_lines(argc, argv, str, ary);
11075}
11076
11077static VALUE
11078rb_str_each_byte_size(VALUE str, VALUE args, VALUE eobj)
11079{
11080 return LEN2NUM(RSTRING_LEN(str));
11081}
11082
11083static VALUE
11084rb_str_enumerate_bytes(VALUE str, VALUE ary)
11085{
11086 rb_len_t i;
11087
11088 for (i=0; i<RSTRING_LEN(str); i++) {
11089 ENUM_ELEM(ary, INT2FIX((unsigned char)RSTRING_PTR(str)[i]));
11090 }
11091 if (ary)
11092 return ary;
11093 else
11094 return str;
11095}
11096
11097/*
11098 * call-seq:
11099 * each_byte {|byte| ... } -> self
11100 * each_byte -> enumerator
11101 *
11102 * :include: doc/string/each_byte.rdoc
11103 *
11104 */
11105
11106static VALUE
11107rb_str_each_byte(VALUE str)
11108{
11109 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_byte_size);
11110 return rb_str_enumerate_bytes(str, 0);
11111}
11112
11113/*
11114 * call-seq:
11115 * bytes -> array_of_bytes
11116 *
11117 * :include: doc/string/bytes.rdoc
11118 *
11119 */
11120
11121static VALUE
11122rb_str_bytes(VALUE str)
11123{
11124 VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
11125 return rb_str_enumerate_bytes(str, ary);
11126}
11127
11128static VALUE
11129rb_str_each_char_size(VALUE str, VALUE args, VALUE eobj)
11130{
11131 return rb_str_length(str);
11132}
11133
11134static VALUE
11135rb_str_enumerate_chars(VALUE str, VALUE ary)
11136{
11137 VALUE orig = str;
11138 rb_len_t i, len, n;
11139 const char *ptr;
11140 rb_encoding *enc;
11141
11142 str = rb_str_new_frozen(str);
11143 ptr = RSTRING_PTR(str);
11144 len = RSTRING_LEN(str);
11145 enc = rb_enc_get(str);
11146
11148 for (i = 0; i < len; i += n) {
11149 n = rb_enc_fast_mbclen(ptr + i, ptr + len, enc);
11150 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
11151 }
11152 }
11153 else {
11154 for (i = 0; i < len; i += n) {
11155 n = rb_enc_mbclen(ptr + i, ptr + len, enc);
11156 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
11157 }
11158 }
11159 RB_GC_GUARD(str);
11160 if (ary)
11161 return ary;
11162 else
11163 return orig;
11164}
11165
11166/*
11167 * call-seq:
11168 * each_char {|char| ... } -> self
11169 * each_char -> enumerator
11170 *
11171 * :include: doc/string/each_char.rdoc
11172 *
11173 */
11174
11175static VALUE
11176rb_str_each_char(VALUE str)
11177{
11178 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
11179 return rb_str_enumerate_chars(str, 0);
11180}
11181
11182/*
11183 * call-seq:
11184 * chars -> array_of_characters
11185 *
11186 * :include: doc/string/chars.rdoc
11187 *
11188 */
11189
11190static VALUE
11191rb_str_chars(VALUE str)
11192{
11193 VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
11194 return rb_str_enumerate_chars(str, ary);
11195}
11196
11197static VALUE
11198rb_str_enumerate_codepoints(VALUE str, VALUE ary)
11199{
11200 VALUE orig = str;
11201 int n;
11202 unsigned int c;
11203 const char *ptr, *end;
11204 rb_encoding *enc;
11205 int enc_asciicompat;
11206
11207 if (single_byte_optimizable(str))
11208 return rb_str_enumerate_bytes(str, ary);
11209
11210 str = rb_str_new_frozen(str);
11211 ptr = RSTRING_PTR(str);
11212 end = RSTRING_END(str);
11213 enc = STR_ENC_GET(str);
11214 enc_asciicompat = rb_enc_asciicompat(enc);
11215
11216 while (ptr < end) {
11217 /* Fast path: ASCII byte in an ASCII-compatible encoding is its own codepoint;
11218 * skip rb_enc_codepoint_len and return the byte directly.
11219 */
11220 n = 1;
11221 c = (enc_asciicompat && ISASCII(*ptr)) ?
11222 (unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11223 ENUM_ELEM(ary, UINT2NUM(c));
11224 ptr += n;
11225 }
11226 RB_GC_GUARD(str);
11227 if (ary)
11228 return ary;
11229 else
11230 return orig;
11231}
11232
11233/*
11234 * call-seq:
11235 * each_codepoint {|codepoint| ... } -> self
11236 * each_codepoint -> enumerator
11237 *
11238 * :include: doc/string/each_codepoint.rdoc
11239 *
11240 */
11241
11242static VALUE
11243rb_str_each_codepoint(VALUE str)
11244{
11245 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
11246 return rb_str_enumerate_codepoints(str, 0);
11247}
11248
11249/*
11250 * call-seq:
11251 * codepoints -> array_of_integers
11252 *
11253 * :include: doc/string/codepoints.rdoc
11254 *
11255 */
11256
11257static VALUE
11258rb_str_codepoints(VALUE str)
11259{
11260 VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
11261 return rb_str_enumerate_codepoints(str, ary);
11262}
11263
11264static regex_t *
11265get_reg_grapheme_cluster(rb_encoding *enc)
11266{
11267 int encidx = rb_enc_to_index(enc);
11268
11269 const OnigUChar source_ascii[] = "\\X";
11270 const OnigUChar *source = source_ascii;
11271 size_t source_len = sizeof(source_ascii) - 1;
11272
11273 switch (encidx) {
11274#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11275#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11276#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11277#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11278#define CASE_UTF(e) \
11279 case ENCINDEX_UTF_##e: { \
11280 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11281 source = source_UTF_##e; \
11282 source_len = sizeof(source_UTF_##e); \
11283 break; \
11284 }
11285 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11286#undef CASE_UTF
11287#undef CHARS_16BE
11288#undef CHARS_16LE
11289#undef CHARS_32BE
11290#undef CHARS_32LE
11291 }
11292
11293 regex_t *reg_grapheme_cluster;
11294 OnigErrorInfo einfo;
11295 int r = onig_new(&reg_grapheme_cluster, source, source + source_len,
11296 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11297 if (r) {
11298 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11299 onig_error_code_to_str(message, r, &einfo);
11300 rb_fatal("cannot compile grapheme cluster regexp: %s", (char *)message);
11301 }
11302
11303 return reg_grapheme_cluster;
11304}
11305
11306static regex_t *
11307get_cached_reg_grapheme_cluster(rb_encoding *enc)
11308{
11309 int encidx = rb_enc_to_index(enc);
11310 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11311
11312 if (encidx == rb_utf8_encindex()) {
11313 if (!reg_grapheme_cluster_utf8) {
11314 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11315 }
11316
11317 return reg_grapheme_cluster_utf8;
11318 }
11319
11320 return NULL;
11321}
11322
11323static VALUE
11324rb_str_each_grapheme_cluster_size(VALUE str, VALUE args, VALUE eobj)
11325{
11326 size_t grapheme_cluster_count = 0;
11327 rb_encoding *enc = get_encoding(str);
11328 const char *ptr, *end;
11329
11330 if (!rb_enc_unicode_p(enc)) {
11331 return rb_str_length(str);
11332 }
11333
11334 bool cached_reg_grapheme_cluster = true;
11335 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11336 if (!reg_grapheme_cluster) {
11337 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11338 cached_reg_grapheme_cluster = false;
11339 }
11340
11341 ptr = RSTRING_PTR(str);
11342 end = RSTRING_END(str);
11343
11344 while (ptr < end) {
11345 OnigPosition len = onig_match(reg_grapheme_cluster,
11346 (const OnigUChar *)ptr, (const OnigUChar *)end,
11347 (const OnigUChar *)ptr, NULL, 0);
11348 if (len <= 0) break;
11349 grapheme_cluster_count++;
11350 ptr += len;
11351 }
11352
11353 if (!cached_reg_grapheme_cluster) {
11354 onig_free(reg_grapheme_cluster);
11355 }
11356
11357 return SIZET2NUM(grapheme_cluster_count);
11358}
11359
11360static VALUE
11361rb_str_enumerate_grapheme_clusters(VALUE str, VALUE ary)
11362{
11363 VALUE orig = str;
11364 rb_encoding *enc = get_encoding(str);
11365 const char *ptr0, *ptr, *end;
11366
11367 if (!rb_enc_unicode_p(enc)) {
11368 return rb_str_enumerate_chars(str, ary);
11369 }
11370
11371 if (!ary) str = rb_str_new_frozen(str);
11372
11373 bool cached_reg_grapheme_cluster = true;
11374 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11375 if (!reg_grapheme_cluster) {
11376 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11377 cached_reg_grapheme_cluster = false;
11378 }
11379
11380 ptr0 = ptr = RSTRING_PTR(str);
11381 end = RSTRING_END(str);
11382
11383 while (ptr < end) {
11384 OnigPosition len = onig_match(reg_grapheme_cluster,
11385 (const OnigUChar *)ptr, (const OnigUChar *)end,
11386 (const OnigUChar *)ptr, NULL, 0);
11387 if (len <= 0) break;
11388 ENUM_ELEM(ary, rb_str_subseq(str, ptr-ptr0, len));
11389 ptr += len;
11390 }
11391
11392 if (!cached_reg_grapheme_cluster) {
11393 onig_free(reg_grapheme_cluster);
11394 }
11395
11396 RB_GC_GUARD(str);
11397 if (ary)
11398 return ary;
11399 else
11400 return orig;
11401}
11402
11403/*
11404 * call-seq:
11405 * each_grapheme_cluster {|grapheme_cluster| ... } -> self
11406 * each_grapheme_cluster -> enumerator
11407 *
11408 * :include: doc/string/each_grapheme_cluster.rdoc
11409 *
11410 */
11411
11412static VALUE
11413rb_str_each_grapheme_cluster(VALUE str)
11414{
11415 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_grapheme_cluster_size);
11416 return rb_str_enumerate_grapheme_clusters(str, 0);
11417}
11418
11419/*
11420 * call-seq:
11421 * grapheme_clusters -> array_of_grapheme_clusters
11422 *
11423 * :include: doc/string/grapheme_clusters.rdoc
11424 *
11425 */
11426
11427static VALUE
11428rb_str_grapheme_clusters(VALUE str)
11429{
11430 VALUE ary = WANTARRAY("grapheme_clusters", rb_str_strlen(str));
11431 return rb_str_enumerate_grapheme_clusters(str, ary);
11432}
11433
11434static rb_len_t
11435chopped_length(VALUE str)
11436{
11437 rb_encoding *enc = STR_ENC_GET(str);
11438 const char *p, *p2, *beg, *end;
11439
11440 beg = RSTRING_PTR(str);
11441 end = beg + RSTRING_LEN(str);
11442 if (beg >= end) return 0;
11443 p = rb_enc_prev_char(beg, end, end, enc);
11444 if (!p) return 0;
11445 if (p > beg && rb_enc_ascget(p, end, 0, enc) == '\n') {
11446 p2 = rb_enc_prev_char(beg, p, end, enc);
11447 if (p2 && rb_enc_ascget(p2, end, 0, enc) == '\r') p = p2;
11448 }
11449 return p - beg;
11450}
11451
11452/*
11453 * call-seq:
11454 * chop! -> self or nil
11455 *
11456 * Like String#chop, except that:
11457 *
11458 * - Removes trailing characters from +self+ (not from a copy of +self+).
11459 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11460 *
11461 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11462 */
11463
11464static VALUE
11465rb_str_chop_bang(VALUE str)
11466{
11467 str_modify_keep_cr(str);
11468 if (RSTRING_LEN(str) > 0) {
11469 rb_len_t len;
11470 len = chopped_length(str);
11471 STR_SET_LEN(str, len);
11472 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11473 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11475 }
11476 return str;
11477 }
11478 return Qnil;
11479}
11480
11481
11482/*
11483 * call-seq:
11484 * chop -> new_string
11485 *
11486 * :include: doc/string/chop.rdoc
11487 *
11488 */
11489
11490static VALUE
11491rb_str_chop(VALUE str)
11492{
11493 return rb_str_subseq(str, 0, chopped_length(str));
11494}
11495
11496static rb_len_t
11497smart_chomp(VALUE str, const char *e, const char *p)
11498{
11499 rb_encoding *enc = rb_enc_get(str);
11500 if (rb_enc_mbminlen(enc) > 1) {
11501 /* a receiver shorter than one character has nothing to chomp */
11502 if (e - p < rb_enc_mbminlen(enc)) return e - p;
11503 const char *pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11504 if (rb_enc_is_newline(pp, e, enc)) {
11505 e = pp;
11506 }
11507 pp = e - rb_enc_mbminlen(enc);
11508 if (pp >= p) {
11509 pp = rb_enc_left_char_head(p, pp, e, enc);
11510 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11511 e = pp;
11512 }
11513 }
11514 }
11515 else {
11516 switch (*(e-1)) { /* not e[-1] to get rid of VC bug */
11517 case '\n':
11518 if (--e > p && *(e-1) == '\r') {
11519 --e;
11520 }
11521 break;
11522 case '\r':
11523 --e;
11524 break;
11525 }
11526 }
11527 return e - p;
11528}
11529
11530static rb_len_t
11531chompped_length(VALUE str, VALUE rs)
11532{
11533 rb_encoding *enc;
11534 int newline;
11535 const char *pp, *e, *rsptr;
11536 rb_len_t rslen;
11537 const char *const p = RSTRING_PTR(str);
11538 rb_len_t len = RSTRING_LEN(str);
11539
11540 if (len == 0) return 0;
11541 e = p + len;
11542 if (rs == rb_default_rs) {
11543 return smart_chomp(str, e, p);
11544 }
11545
11546 enc = rb_enc_get(str);
11547 RSTRING_GETMEM(rs, rsptr, rslen);
11548 if (rslen == 0) {
11549 if (rb_enc_mbminlen(enc) > 1) {
11550 while (e - p >= rb_enc_mbminlen(enc)) {
11551 pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11552 if (!rb_enc_is_newline(pp, e, enc)) break;
11553 e = pp;
11554 pp -= rb_enc_mbminlen(enc);
11555 if (pp >= p) {
11556 pp = rb_enc_left_char_head(p, pp, e, enc);
11557 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11558 e = pp;
11559 }
11560 }
11561 }
11562 }
11563 else {
11564 while (e > p && *(e-1) == '\n') {
11565 --e;
11566 if (e > p && *(e-1) == '\r')
11567 --e;
11568 }
11569 }
11570 return e - p;
11571 }
11572 if (rslen > len) return len;
11573
11574 enc = rb_enc_get(rs);
11575 newline = rsptr[rslen-1];
11576 if (rslen == rb_enc_mbminlen(enc)) {
11577 if (rslen == 1) {
11578 if (newline == '\n')
11579 return smart_chomp(str, e, p);
11580 }
11581 else {
11582 if (rb_enc_is_newline(rsptr, rsptr+rslen, enc))
11583 return smart_chomp(str, e, p);
11584 }
11585 }
11586
11587 enc = rb_enc_check(str, rs);
11588 if (is_broken_string(rs)) {
11589 return len;
11590 }
11591 pp = e - rslen;
11592 if (p[len-1] == newline &&
11593 (rslen <= 1 ||
11594 memcmp(rsptr, pp, rslen) == 0)) {
11595 if (at_char_boundary(p, pp, e, enc))
11596 return len - rslen;
11597 RB_GC_GUARD(rs);
11598 }
11599 return len;
11600}
11601
11607static VALUE
11608chomp_rs(int argc, const VALUE *argv)
11609{
11610 rb_check_arity(argc, 0, 1);
11611 if (argc > 0) {
11612 VALUE rs = argv[0];
11613 if (!NIL_P(rs)) StringValue(rs);
11614 return rs;
11615 }
11616 else {
11617 return rb_rs;
11618 }
11619}
11620
11621static VALUE
11622str_shrink(VALUE str, rb_len_t len)
11623{
11624 str_modify_keep_cr(str);
11625 STR_SET_LEN(str, len);
11626 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11627 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11629 }
11630 return str;
11631}
11632
11633VALUE
11634rb_str_chomp_string(VALUE str, VALUE rs)
11635{
11636 rb_len_t olen = RSTRING_LEN(str);
11637 rb_len_t len = chompped_length(str, rs);
11638 if (len >= olen) return Qnil;
11639 return str_shrink(str, len);
11640}
11641
11642/*
11643 * call-seq:
11644 * chomp!(line_sep = $/) -> self or nil
11645 *
11646 * Like String#chomp, except that:
11647 *
11648 * - Removes trailing characters from +self+ (not from a copy of +self+).
11649 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11650 *
11651 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11652 */
11653
11654static VALUE
11655rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
11656{
11657 VALUE rs;
11658 str_modifiable(str);
11659 if (RSTRING_LEN(str) == 0 && argc < 2) return Qnil;
11660 rs = chomp_rs(argc, argv);
11661 if (NIL_P(rs)) return Qnil;
11662 return rb_str_chomp_string(str, rs);
11663}
11664
11665
11666/*
11667 * call-seq:
11668 * chomp(line_sep = $/) -> new_string
11669 *
11670 * :include: doc/string/chomp.rdoc
11671 *
11672 */
11673
11674static VALUE
11675rb_str_chomp(int argc, VALUE *argv, VALUE str)
11676{
11677 VALUE rs = chomp_rs(argc, argv);
11678 if (NIL_P(rs)) return str_duplicate(rb_cString, str);
11679 return rb_str_subseq(str, 0, chompped_length(str, rs));
11680}
11681
11682static void
11683tr_setup_table_multi(char table[TR_TABLE_SIZE], VALUE *tablep, VALUE *ctablep,
11684 VALUE str, int num_selectors, VALUE *selectors)
11685{
11686 int i;
11687
11688 for (i=0; i<num_selectors; i++) {
11689 VALUE selector = selectors[i];
11690 rb_encoding *enc;
11691
11692 StringValue(selector);
11693 enc = rb_enc_check(str, selector);
11694 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11695 }
11696}
11697
11698static rb_len_t
11699lstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11700{
11701 const char *const start = s;
11702
11703 if (!s || s >= e) return 0;
11704
11705 /* remove spaces at head */
11706 if (single_byte_optimizable(str)) {
11707 while (s < e && (*s == '\0' || ascii_isspace(*s))) s++;
11708 }
11709 else {
11710 while (s < e) {
11711 int n;
11712 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11713
11714 if (cc && !rb_isspace(cc)) break;
11715 s += n;
11716 }
11717 }
11718 return s - start;
11719}
11720
11721static rb_len_t
11722lstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11723 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11724{
11725 const char *const start = s;
11726
11727 if (!s || s >= e) return 0;
11728
11729 /* remove leading characters in the table */
11730 while (s < e) {
11731 int n;
11732 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11733
11734 if (!tr_find(cc, table, del, nodel)) break;
11735 s += n;
11736 }
11737 return s - start;
11738}
11739
11740/*
11741 * call-seq:
11742 * lstrip!(*selectors) -> self or nil
11743 *
11744 * Like String#lstrip, except that:
11745 *
11746 * - Performs stripping in +self+ (not in a copy of +self+).
11747 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11748 *
11749 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11750 */
11751
11752static VALUE
11753rb_str_lstrip_bang(int argc, VALUE *argv, VALUE str)
11754{
11755 rb_encoding *enc;
11756 char *start;
11757 rb_len_t olen, loffset;
11758
11759 str_modify_keep_cr(str);
11760 enc = STR_ENC_GET(str);
11761 RSTRING_GETMEM(str, start, olen);
11762 if (argc > 0) {
11763 char table[TR_TABLE_SIZE];
11764 VALUE del = 0, nodel = 0;
11765
11766 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11767
11768 /* the selector conversion may have modified str */
11769 str_modify_keep_cr(str);
11770 enc = STR_ENC_GET(str);
11771 RSTRING_GETMEM(str, start, olen);
11772
11773 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11774 }
11775 else {
11776 loffset = lstrip_offset(str, start, start+olen, enc);
11777 }
11778
11779 if (loffset > 0) {
11780 rb_len_t len = olen-loffset;
11781 memmove(start, start + loffset, len);
11782 STR_SET_LEN(str, len);
11783 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11784 return str;
11785 }
11786 return Qnil;
11787}
11788
11789
11790/*
11791 * call-seq:
11792 * lstrip(*selectors) -> new_string
11793 *
11794 * Returns a copy of +self+ with leading whitespace removed;
11795 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11796 *
11797 * whitespace = "\x00\t\n\v\f\r "
11798 * s = whitespace + 'abc' + whitespace
11799 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11800 * s.lstrip
11801 * # => "abc\u0000\t\n\v\f\r "
11802 *
11803 * If +selectors+ are given, removes characters of +selectors+ from the beginning of +self+:
11804 *
11805 * s = "---abc+++"
11806 * s.lstrip("-") # => "abc+++"
11807 *
11808 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11809 * and may use any of its valid forms, including negation, ranges, and escapes:
11810 *
11811 * "01234abc56789".lstrip("0-9") # "abc56789"
11812 * "01234abc56789".lstrip("0-9", "^4-6") # "4abc56789"
11813 *
11814 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11815 */
11816
11817static VALUE
11818rb_str_lstrip(int argc, VALUE *argv, VALUE str)
11819{
11820 const char *start;
11821 rb_len_t len, loffset;
11822
11823 RSTRING_GETMEM(str, start, len);
11824 if (argc > 0) {
11825 char table[TR_TABLE_SIZE];
11826 VALUE del = 0, nodel = 0;
11827
11828 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11829
11830 /* the selector conversion may have modified str */
11831 RSTRING_GETMEM(str, start, len);
11832
11833 loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel);
11834 }
11835 else {
11836 loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
11837 }
11838 if (loffset <= 0) return str_duplicate(rb_cString, str);
11839 return rb_str_subseq(str, loffset, len - loffset);
11840}
11841
11842static rb_len_t
11843rstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11844{
11845 const char *t;
11846
11847 rb_str_check_dummy_enc(enc);
11848 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11849 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11850 }
11851 if (!s || s >= e) return 0;
11852 t = e;
11853
11854 /* remove trailing spaces or '\0's */
11855 if (single_byte_optimizable(str)) {
11856 unsigned char c;
11857 while (s < t && ((c = *(t-1)) == '\0' || ascii_isspace(c))) t--;
11858 }
11859 else {
11860 const char *tp;
11861
11862 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11863 unsigned int c = rb_enc_codepoint(tp, e, enc);
11864 if (c && !rb_isspace(c)) break;
11865 t = tp;
11866 }
11867 }
11868 return e - t;
11869}
11870
11871static rb_len_t
11872rstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11873 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11874{
11875 const char *t, *tp;
11876
11877 rb_str_check_dummy_enc(enc);
11878 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11879 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11880 }
11881 if (!s || s >= e) return 0;
11882 t = e;
11883
11884 /* remove trailing characters in the table */
11885 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11886 unsigned int c = rb_enc_codepoint(tp, e, enc);
11887 if (!tr_find(c, table, del, nodel)) break;
11888 t = tp;
11889 }
11890
11891 return e - t;
11892}
11893
11894/*
11895 * call-seq:
11896 * rstrip!(*selectors) -> self or nil
11897 *
11898 * Like String#rstrip, except that:
11899 *
11900 * - Performs stripping in +self+ (not in a copy of +self+).
11901 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11902 *
11903 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11904 */
11905
11906static VALUE
11907rb_str_rstrip_bang(int argc, VALUE *argv, VALUE str)
11908{
11909 rb_encoding *enc;
11910 char *start;
11911 rb_len_t olen, roffset;
11912
11913 str_modify_keep_cr(str);
11914 enc = STR_ENC_GET(str);
11915 RSTRING_GETMEM(str, start, olen);
11916 if (argc > 0) {
11917 char table[TR_TABLE_SIZE];
11918 VALUE del = 0, nodel = 0;
11919
11920 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11921
11922 /* the selector conversion may have modified str */
11923 str_modify_keep_cr(str);
11924 enc = STR_ENC_GET(str);
11925 RSTRING_GETMEM(str, start, olen);
11926
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) {
11933 rb_len_t len = olen - roffset;
11934
11935 STR_SET_LEN(str, len);
11936 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11937 return str;
11938 }
11939 return Qnil;
11940}
11941
11942
11943/*
11944 * call-seq:
11945 * rstrip(*selectors) -> new_string
11946 *
11947 * Returns a copy of +self+ with trailing whitespace removed;
11948 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11949 *
11950 * whitespace = "\x00\t\n\v\f\r "
11951 * s = whitespace + 'abc' + whitespace
11952 * s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11953 * s.rstrip # => "\u0000\t\n\v\f\r abc"
11954 *
11955 * If +selectors+ are given, removes characters of +selectors+ from the end of +self+:
11956 *
11957 * s = "---abc+++"
11958 * s.rstrip("+") # => "---abc"
11959 *
11960 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11961 * and may use any of its valid forms, including negation, ranges, and escapes:
11962 *
11963 * "01234abc56789".rstrip("0-9") # "01234abc"
11964 * "01234abc56789".rstrip("0-9", "^4-6") # "01234abc56"
11965 *
11966 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11967 */
11968
11969static VALUE
11970rb_str_rstrip(int argc, VALUE *argv, VALUE str)
11971{
11972 rb_encoding *enc;
11973 const char *start;
11974 rb_len_t olen, roffset;
11975
11976 enc = STR_ENC_GET(str);
11977 RSTRING_GETMEM(str, start, olen);
11978 if (argc > 0) {
11979 char table[TR_TABLE_SIZE];
11980 VALUE del = 0, nodel = 0;
11981
11982 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11983
11984 /* the selector conversion may have modified str */
11985 enc = STR_ENC_GET(str);
11986
11987 RSTRING_GETMEM(str, start, olen);
11988 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11989 }
11990 else {
11991 roffset = rstrip_offset(str, start, start+olen, enc);
11992 }
11993 if (roffset <= 0) return str_duplicate(rb_cString, str);
11994 return rb_str_subseq(str, 0, olen-roffset);
11995}
11996
11997
11998/*
11999 * call-seq:
12000 * strip!(*selectors) -> self or nil
12001 *
12002 * Like String#strip, except that:
12003 *
12004 * - Any modifications are made to +self+.
12005 * - Returns +self+ if any modification are made, +nil+ otherwise.
12006 *
12007 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12008 */
12009
12010static VALUE
12011rb_str_strip_bang(int argc, VALUE *argv, VALUE str)
12012{
12013 char *start;
12014 rb_len_t olen, loffset, roffset;
12015 rb_encoding *enc;
12016
12017 str_modify_keep_cr(str);
12018 enc = STR_ENC_GET(str);
12019 RSTRING_GETMEM(str, start, olen);
12020
12021 if (argc > 0) {
12022 char table[TR_TABLE_SIZE];
12023 VALUE del = 0, nodel = 0;
12024
12025 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12026
12027 /* the selector conversion may have modified str */
12028 str_modify_keep_cr(str);
12029 enc = STR_ENC_GET(str);
12030 RSTRING_GETMEM(str, start, olen);
12031
12032 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12033 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12034 }
12035 else {
12036 loffset = lstrip_offset(str, start, start+olen, enc);
12037 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12038 }
12039
12040 if (loffset > 0 || roffset > 0) {
12041 rb_len_t len = olen-roffset;
12042 if (loffset > 0) {
12043 len -= loffset;
12044 memmove(start, start + loffset, len);
12045 }
12046 STR_SET_LEN(str, len);
12047 TERM_FILL(start+len, rb_enc_mbminlen(enc));
12048 return str;
12049 }
12050 return Qnil;
12051}
12052
12053
12054/*
12055 * call-seq:
12056 * strip(*selectors) -> new_string
12057 *
12058 * Returns a copy of +self+ with leading and trailing whitespace removed;
12059 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
12060 *
12061 * whitespace = "\x00\t\n\v\f\r "
12062 * s = whitespace + 'abc' + whitespace
12063 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
12064 * s.strip # => "abc"
12065 *
12066 * If +selectors+ are given, removes characters of +selectors+ from both ends of +self+:
12067 *
12068 * s = "---abc+++"
12069 * s.strip("-+") # => "abc"
12070 * s.strip("+-") # => "abc"
12071 *
12072 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
12073 * and may use any of its valid forms, including negation, ranges, and escapes:
12074 *
12075 * "01234abc56789".strip("0-9") # "abc"
12076 * "01234abc56789".strip("0-9", "^4-6") # "4abc56"
12077 *
12078 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
12079 */
12080
12081static VALUE
12082rb_str_strip(int argc, VALUE *argv, VALUE str)
12083{
12084 const char *start;
12085 rb_len_t olen, loffset, roffset;
12086 rb_encoding *enc = STR_ENC_GET(str);
12087
12088 RSTRING_GETMEM(str, start, olen);
12089
12090 if (argc > 0) {
12091 char table[TR_TABLE_SIZE];
12092 VALUE del = 0, nodel = 0;
12093
12094 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12095
12096 /* the selector conversion may have modified str */
12097 enc = STR_ENC_GET(str);
12098 RSTRING_GETMEM(str, start, olen);
12099
12100 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12101 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12102 }
12103 else {
12104 loffset = lstrip_offset(str, start, start+olen, enc);
12105 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12106 }
12107
12108 if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
12109 return rb_str_subseq(str, loffset, olen-loffset-roffset);
12110}
12111
12112static VALUE
12113scan_once(VALUE str, VALUE pat, rb_len_t *start, int set_backref_str)
12114{
12115 VALUE result = Qnil;
12116 rb_len_t end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12117 if (pos >= 0) {
12118 VALUE match = Qnil;
12119 if (BUILTIN_TYPE(pat) == T_STRING) {
12120 end = pos + RSTRING_LEN(pat);
12121 }
12122 else {
12123 match = rb_backref_get();
12124 pos = RMATCH_BEG(match, 0);
12125 end = RMATCH_END(match, 0);
12126 }
12127
12128 if (pos == end) {
12129 rb_encoding *enc = STR_ENC_GET(str);
12130 /*
12131 * Always consume at least one character of the input string
12132 */
12133 if (RSTRING_LEN(str) > end)
12134 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12135 RSTRING_END(str), enc);
12136 else
12137 *start = end + 1;
12138 }
12139 else {
12140 *start = end;
12141 }
12142
12143 if (NIL_P(match) || RMATCH_NREGS(match) == 1) {
12144 result = rb_str_subseq(str, pos, end - pos);
12145 return result;
12146 }
12147 else {
12148 int num_regs = RMATCH_NREGS(match);
12149 result = rb_ary_new2(num_regs);
12150 for (int i = 1; i < num_regs; i++) {
12151 VALUE s = Qnil;
12152 if (RMATCH_BEG(match, i) >= 0) {
12153 s = rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12154 }
12155
12156 rb_ary_push(result, s);
12157 }
12158 }
12159
12160 RB_GC_GUARD(match);
12161 }
12162
12163 return result;
12164}
12165
12166
12167/*
12168 * call-seq:
12169 * scan(pattern) -> array_of_results
12170 * scan(pattern) {|result| ... } -> self
12171 *
12172 * :include: doc/string/scan.rdoc
12173 *
12174 */
12175
12176static VALUE
12177rb_str_scan(VALUE str, VALUE pat)
12178{
12179 VALUE result;
12180 rb_len_t start = 0;
12181 rb_len_t last = -1, prev = 0;
12182 const char *p = RSTRING_PTR(str);
12183 rb_len_t len = RSTRING_LEN(str);
12184
12185 pat = get_pat_quoted(pat, 1);
12186 mustnot_broken(str);
12187 if (!rb_block_given_p()) {
12188 VALUE ary = rb_ary_new();
12189
12190 while (!NIL_P(result = scan_once(str, pat, &start, 0))) {
12191 last = prev;
12192 prev = start;
12193 rb_ary_push(ary, result);
12194 }
12195 if (last >= 0) rb_pat_search(pat, str, last, 1);
12196 else rb_backref_set(Qnil);
12197 return ary;
12198 }
12199
12200 while (!NIL_P(result = scan_once(str, pat, &start, 1))) {
12201 last = prev;
12202 prev = start;
12203 rb_yield(result);
12204 str_mod_check(str, p, len);
12205 }
12206 if (last >= 0) rb_pat_search(pat, str, last, 1);
12207 return str;
12208}
12209
12210
12211/*
12212 * call-seq:
12213 * hex -> integer
12214 *
12215 * Interprets the leading substring of +self+ as hexadecimal, possibly signed;
12216 * returns its value as an integer.
12217 *
12218 * The leading substring is interpreted as hexadecimal when it begins with:
12219 *
12220 * - One or more character representing hexadecimal digits
12221 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
12222 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit:
12223 *
12224 * 'f'.hex # => 15
12225 * '11'.hex # => 17
12226 * 'FFF'.hex # => 4095
12227 * 'fffg'.hex # => 4095
12228 * 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not.
12229 * 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not.
12230 * 'deadbeef'.hex # => 3735928559
12231 *
12232 * - <tt>'0x'</tt> or <tt>'0X'</tt>, followed by one or more hexadecimal digits:
12233 *
12234 * '0xfff'.hex # => 4095
12235 * '0xfffg'.hex # => 4095
12236 *
12237 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
12238 *
12239 * '-fff'.hex # => -4095
12240 * '-0xFFF'.hex # => -4095
12241 *
12242 * For any substring not described above, returns zero:
12243 *
12244 * 'xxx'.hex # => 0
12245 * ''.hex # => 0
12246 *
12247 * Note that, unlike #oct, this method interprets only hexadecimal,
12248 * and not binary, octal, or decimal notations:
12249 *
12250 * '0b111'.hex # => 45329
12251 * '0o777'.hex # => 0
12252 * '0d999'.hex # => 55705
12253 *
12254 * Related: See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
12255 */
12256
12257static VALUE
12258rb_str_hex(VALUE str)
12259{
12260 return rb_str_to_inum(str, 16, FALSE);
12261}
12262
12263
12264/*
12265 * call-seq:
12266 * oct -> integer
12267 *
12268 * Interprets the leading substring of +self+ as octal, binary, decimal, or hexadecimal, possibly signed;
12269 * returns their value as an integer.
12270 *
12271 * In brief:
12272 *
12273 * # Interpreted as octal.
12274 * '777'.oct # => 511
12275 * '777x'.oct # => 511
12276 * '0777'.oct # => 511
12277 * '0o777'.oct # => 511
12278 * '-777'.oct # => -511
12279 * # Not interpreted as octal.
12280 * '0b111'.oct # => 7 # Interpreted as binary.
12281 * '0d999'.oct # => 999 # Interpreted as decimal.
12282 * '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
12283 *
12284 * The leading substring is interpreted as octal when it begins with:
12285 *
12286 * - One or more character representing octal digits
12287 * (each in the range <tt>'0'..'7'</tt>);
12288 * the string to be interpreted ends at the first character that does not represent an octal digit:
12289 *
12290 * '7'.oct @ => 7
12291 * '11'.oct # => 9
12292 * '777'.oct # => 511
12293 * '0777'.oct # => 511
12294 * '7778'.oct # => 511
12295 * '777x'.oct # => 511
12296 *
12297 * - <tt>'0o'</tt>, followed by one or more octal digits:
12298 *
12299 * '0o777'.oct # => 511
12300 * '0o7778'.oct # => 511
12301 *
12302 * The leading substring is _not_ interpreted as octal when it begins with:
12303 *
12304 * - <tt>'0b'</tt>, followed by one or more characters representing binary digits
12305 * (each in the range <tt>'0'..'1'</tt>);
12306 * the string to be interpreted ends at the first character that does not represent a binary digit.
12307 * the string is interpreted as binary digits (base 2):
12308 *
12309 * '0b111'.oct # => 7
12310 * '0b1112'.oct # => 7
12311 *
12312 * - <tt>'0d'</tt>, followed by one or more characters representing decimal digits
12313 * (each in the range <tt>'0'..'9'</tt>);
12314 * the string to be interpreted ends at the first character that does not represent a decimal digit.
12315 * the string is interpreted as decimal digits (base 10):
12316 *
12317 * '0d999'.oct # => 999
12318 * '0d999x'.oct # => 999
12319 *
12320 * - <tt>'0x'</tt>, followed by one or more characters representing hexadecimal digits
12321 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
12322 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit.
12323 * the string is interpreted as hexadecimal digits (base 16):
12324 *
12325 * '0xfff'.oct # => 4095
12326 * '0xfffg'.oct # => 4095
12327 *
12328 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
12329 *
12330 * '-777'.oct # => -511
12331 * '-0777'.oct # => -511
12332 * '-0b111'.oct # => -7
12333 * '-0xfff'.oct # => -4095
12334 *
12335 * For any substring not described above, returns zero:
12336 *
12337 * 'foo'.oct # => 0
12338 * ''.oct # => 0
12339 *
12340 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
12341 */
12342
12343static VALUE
12344rb_str_oct(VALUE str)
12345{
12346 return rb_str_to_inum(str, -8, FALSE);
12347}
12348
12349#ifndef HAVE_CRYPT_R
12350# include "ruby/thread_native.h"
12351# include "ruby/atomic.h"
12352
12353static struct {
12354 rb_nativethread_lock_t lock;
12355} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12356#endif
12357
12358/*
12359 * call-seq:
12360 * crypt(salt_str) -> new_string
12361 *
12362 * Returns the string generated by calling <code>crypt(3)</code>
12363 * standard library function with <code>str</code> and
12364 * <code>salt_str</code>, in this order, as its arguments. Please do
12365 * not use this method any longer. It is legacy; provided only for
12366 * backward compatibility with ruby scripts in earlier days. It is
12367 * bad to use in contemporary programs for several reasons:
12368 *
12369 * * Behaviour of C's <code>crypt(3)</code> depends on the OS it is
12370 * run. The generated string lacks data portability.
12371 *
12372 * * On some OSes such as Mac OS, <code>crypt(3)</code> never fails
12373 * (i.e. silently ends up in unexpected results).
12374 *
12375 * * On some OSes such as Mac OS, <code>crypt(3)</code> is not
12376 * thread safe.
12377 *
12378 * * So-called "traditional" usage of <code>crypt(3)</code> is very
12379 * very very weak. According to its manpage, Linux's traditional
12380 * <code>crypt(3)</code> output has only 2**56 variations; too
12381 * easy to brute force today. And this is the default behaviour.
12382 *
12383 * * In order to make things robust some OSes implement so-called
12384 * "modular" usage. To go through, you have to do a complex
12385 * build-up of the <code>salt_str</code> parameter, by hand.
12386 * Failure in generation of a proper salt string tends not to
12387 * yield any errors; typos in parameters are normally not
12388 * detectable.
12389 *
12390 * * For instance, in the following example, the second invocation
12391 * of String#crypt is wrong; it has a typo in "round=" (lacks
12392 * "s"). However the call does not fail and something unexpected
12393 * is generated.
12394 *
12395 * "foo".crypt("$5$rounds=1000$salt$") # OK, proper usage
12396 * "foo".crypt("$5$round=1000$salt$") # Typo not detected
12397 *
12398 * * Even in the "modular" mode, some hash functions are considered
12399 * archaic and no longer recommended at all; for instance module
12400 * <code>$1$</code> is officially abandoned by its author: see
12401 * http://phk.freebsd.dk/sagas/md5crypt_eol/ . For another
12402 * instance module <code>$3$</code> is considered completely
12403 * broken: see the manpage of FreeBSD.
12404 *
12405 * * On some OS such as Mac OS, there is no modular mode. Yet, as
12406 * written above, <code>crypt(3)</code> on Mac OS never fails.
12407 * This means even if you build up a proper salt string it
12408 * generates a traditional DES hash anyways, and there is no way
12409 * for you to be aware of.
12410 *
12411 * "foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
12412 *
12413 * If for some reason you cannot migrate to other secure contemporary
12414 * password hashing algorithms, install the string-crypt gem and
12415 * <code>require 'string/crypt'</code> to continue using it.
12416 */
12417
12418static VALUE
12419rb_str_crypt(VALUE str, VALUE salt)
12420{
12421#ifdef HAVE_CRYPT_R
12422 VALUE databuf;
12423 struct crypt_data *data;
12424# define CRYPT_END() ALLOCV_END(databuf)
12425#else
12426 char *tmp_buf;
12427 extern char *crypt(const char *, const char *);
12428# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12429#endif
12430 VALUE result;
12431 const char *s, *saltp, *res;
12432#ifdef BROKEN_CRYPT
12433 char salt_8bit_clean[3];
12434#endif
12435
12436 StringValue(salt);
12437 mustnot_wchar(str);
12438 mustnot_wchar(salt);
12439 s = StringValueCStr(str);
12440 saltp = RSTRING_PTR(salt);
12441 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12442 rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
12443 }
12444
12445#ifdef BROKEN_CRYPT
12446 if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) {
12447 salt_8bit_clean[0] = saltp[0] & 0x7f;
12448 salt_8bit_clean[1] = saltp[1] & 0x7f;
12449 salt_8bit_clean[2] = '\0';
12450 saltp = salt_8bit_clean;
12451 }
12452#endif
12453#ifdef HAVE_CRYPT_R
12454 data = ALLOCV(databuf, sizeof(struct crypt_data));
12455# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12456 data->initialized = 0;
12457# endif
12458 res = crypt_r(s, saltp, data);
12459#else
12460 rb_nativethread_lock_lock(&crypt_mutex.lock);
12461 res = crypt(s, saltp);
12462#endif
12463 if (!res) {
12464 int err = errno;
12465 CRYPT_END();
12466 rb_syserr_fail(err, "crypt");
12467 }
12468#ifdef HAVE_CRYPT_R
12469 result = rb_str_new_cstr(res);
12470 CRYPT_END();
12471#else
12472 // We need to copy this buffer because it's static and we need to unlock the mutex
12473 // before allocating a new object (the string to be returned). If we allocate while
12474 // holding the lock, we could run GC which fires the VM barrier and causes a deadlock
12475 // if other ractors are waiting on this lock.
12476 size_t res_size = strlen(res);
12477 tmp_buf = ALLOCA_N(char, res_size); // should be small enough to alloca
12478 memcpy(tmp_buf, res, res_size);
12479 CRYPT_END();
12480 result = rb_str_new(tmp_buf, res_size);
12481#endif
12482 return result;
12483}
12484
12485
12486/*
12487 * call-seq:
12488 * ord -> integer
12489 *
12490 * :include: doc/string/ord.rdoc
12491 *
12492 */
12493
12494static VALUE
12495rb_str_ord(VALUE s)
12496{
12497 unsigned int c;
12498
12499 c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
12500 return UINT2NUM(c);
12501}
12502/*
12503 * call-seq:
12504 * sum(n = 16) -> integer
12505 *
12506 * :include: doc/string/sum.rdoc
12507 *
12508 */
12509
12510static VALUE
12511rb_str_sum(int argc, VALUE *argv, VALUE str)
12512{
12513 int bits = 16;
12514 char *ptr, *p, *pend;
12515 rb_len_t len;
12516 VALUE sum = INT2FIX(0);
12517 unsigned long sum0 = 0;
12518
12519 if (rb_check_arity(argc, 0, 1) && (bits = NUM2INT(argv[0])) < 0) {
12520 bits = 0;
12521 }
12522 ptr = p = RSTRING_PTR(str);
12523 len = RSTRING_LEN(str);
12524 pend = p + len;
12525
12526 while (p < pend) {
12527 if (FIXNUM_MAX - UCHAR_MAX < sum0) {
12528 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12529 str_mod_check(str, ptr, len);
12530 sum0 = 0;
12531 }
12532 sum0 += (unsigned char)*p;
12533 p++;
12534 }
12535
12536 if (bits == 0) {
12537 if (sum0) {
12538 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12539 }
12540 }
12541 else {
12542 if (sum == INT2FIX(0)) {
12543 if (bits < (int)sizeof(long)*CHAR_BIT) {
12544 sum0 &= (((unsigned long)1)<<bits)-1;
12545 }
12546 sum = LONG2FIX(sum0);
12547 }
12548 else {
12549 VALUE mod;
12550
12551 if (sum0) {
12552 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12553 }
12554
12555 mod = rb_funcall(INT2FIX(1), idLTLT, 1, INT2FIX(bits));
12556 mod = rb_funcall(mod, '-', 1, INT2FIX(1));
12557 sum = rb_funcall(sum, '&', 1, mod);
12558 }
12559 }
12560 return sum;
12561}
12562
12563static VALUE
12564rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
12565{
12566 rb_encoding *enc;
12567 VALUE w;
12568 rb_len_t width, len, flen = 1, fclen = 1;
12569 VALUE res;
12570 char *p;
12571 const char *f = " ";
12572 rb_len_t n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12573 VALUE pad;
12574 int singlebyte = 1, cr;
12575 int termlen;
12576
12577 rb_scan_args(argc, argv, "11", &w, &pad);
12578 enc = STR_ENC_GET(str);
12579 width = NUM2LEN(w);
12580 if (argc == 2) {
12581 StringValue(pad);
12582 enc = rb_enc_check(str, pad);
12583 f = RSTRING_PTR(pad);
12584 flen = RSTRING_LEN(pad);
12585 fclen = str_strlen(pad, enc); /* rb_enc_check */
12586 singlebyte = single_byte_optimizable(pad);
12587 if (flen == 0 || fclen == 0) {
12588 rb_raise(rb_eArgError, "zero width padding");
12589 }
12590 }
12591 termlen = rb_enc_mbminlen(enc);
12592 len = str_strlen(str, enc); /* rb_enc_check */
12593 if (width < 0 || len >= width) return str_duplicate(rb_cString, str);
12594 n = width - len;
12595 llen = (jflag == 'l') ? 0 : ((jflag == 'r') ? n : n/2);
12596 rlen = n - llen;
12597 cr = ENC_CODERANGE(str);
12598 if (flen > 1) {
12599 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12600 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12601 }
12602 size = RSTRING_LEN(str);
12603 if ((len = llen / fclen + rlen / fclen) >= RB_LEN_MAX / flen ||
12604 (len *= flen) >= RB_LEN_MAX - llen2 - rlen2 ||
12605 (len += llen2 + rlen2) >= RB_LEN_MAX - size) {
12606 rb_raise(rb_eArgError, "argument too big");
12607 }
12608 len += size;
12609 res = str_enc_new(rb_cString, 0, len, enc);
12610 p = RSTRING_PTR(res);
12611 if (flen <= 1) {
12612 memset(p, *f, llen);
12613 p += llen;
12614 }
12615 else {
12616 while (llen >= fclen) {
12617 memcpy(p,f,flen);
12618 p += flen;
12619 llen -= fclen;
12620 }
12621 if (llen > 0) {
12622 memcpy(p, f, llen2);
12623 p += llen2;
12624 }
12625 }
12626 memcpy(p, RSTRING_PTR(str), size);
12627 p += size;
12628 if (flen <= 1) {
12629 memset(p, *f, rlen);
12630 p += rlen;
12631 }
12632 else {
12633 while (rlen >= fclen) {
12634 memcpy(p,f,flen);
12635 p += flen;
12636 rlen -= fclen;
12637 }
12638 if (rlen > 0) {
12639 memcpy(p, f, rlen2);
12640 p += rlen2;
12641 }
12642 }
12643 TERM_FILL(p, termlen);
12644 STR_SET_LEN(res, p-RSTRING_PTR(res));
12645
12646 if (argc == 2)
12647 cr = ENC_CODERANGE_AND(cr, ENC_CODERANGE(pad));
12648 if (cr != ENC_CODERANGE_BROKEN)
12649 ENC_CODERANGE_SET(res, cr);
12650
12651 RB_GC_GUARD(pad);
12652 return res;
12653}
12654
12655
12656/*
12657 * call-seq:
12658 * ljust(width, pad_string = ' ') -> new_string
12659 *
12660 * :include: doc/string/ljust.rdoc
12661 *
12662 */
12663
12664static VALUE
12665rb_str_ljust(int argc, VALUE *argv, VALUE str)
12666{
12667 return rb_str_justify(argc, argv, str, 'l');
12668}
12669
12670/*
12671 * call-seq:
12672 * rjust(width, pad_string = ' ') -> new_string
12673 *
12674 * :include: doc/string/rjust.rdoc
12675 *
12676 */
12677
12678static VALUE
12679rb_str_rjust(int argc, VALUE *argv, VALUE str)
12680{
12681 return rb_str_justify(argc, argv, str, 'r');
12682}
12683
12684
12685/*
12686 * call-seq:
12687 * center(size, pad_string = ' ') -> new_string
12688 *
12689 * :include: doc/string/center.rdoc
12690 *
12691 */
12692
12693static VALUE
12694rb_str_center(int argc, VALUE *argv, VALUE str)
12695{
12696 return rb_str_justify(argc, argv, str, 'c');
12697}
12698
12699/*
12700 * call-seq:
12701 * partition(pattern) -> [pre_match, first_match, post_match]
12702 *
12703 * :include: doc/string/partition.rdoc
12704 *
12705 */
12706
12707static VALUE
12708rb_str_partition(VALUE str, VALUE sep)
12709{
12710 rb_len_t pos;
12711
12712 sep = get_pat_quoted(sep, 0);
12713 if (RB_TYPE_P(sep, T_REGEXP)) {
12714 if (rb_reg_search(sep, str, 0, 0) < 0) {
12715 goto failed;
12716 }
12717 VALUE match = rb_backref_get();
12718
12719 pos = RMATCH_BEG(match, 0);
12720 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12721 }
12722 else {
12723 pos = rb_str_index(str, sep, 0);
12724 if (pos < 0) goto failed;
12725 }
12726
12727 rb_len_t rpos = pos + RSTRING_LEN(sep);
12728 if (rpos > RSTRING_LEN(str)) goto failed;
12729 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12730 sep,
12731 rb_str_subseq(str, rpos, RSTRING_LEN(str)-rpos));
12732
12733 failed:
12734 return rb_ary_new3(3, str_duplicate(rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12735}
12736
12737/*
12738 * call-seq:
12739 * rpartition(pattern) -> [pre_match, last_match, post_match]
12740 *
12741 * :include: doc/string/rpartition.rdoc
12742 *
12743 */
12744
12745static VALUE
12746rb_str_rpartition(VALUE str, VALUE sep)
12747{
12748 rb_len_t pos;
12749
12750 sep = get_pat_quoted(sep, 0);
12751 if (RB_TYPE_P(sep, T_REGEXP)) {
12752 pos = RSTRING_LEN(str);
12753 if (rb_reg_search(sep, str, pos, 1) < 0) {
12754 goto failed;
12755 }
12756 VALUE match = rb_backref_get();
12757
12758 pos = RMATCH_BEG(match, 0);
12759 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12760 }
12761 else {
12762 /* str may have been modified by #to_str above */
12763 pos = rb_str_sublen(str, RSTRING_LEN(str));
12764 pos = rb_str_rindex(str, sep, pos);
12765 if (pos < 0) {
12766 goto failed;
12767 }
12768 }
12769
12770 rb_len_t rpos = pos + RSTRING_LEN(sep);
12771 if (rpos > RSTRING_LEN(str)) goto failed;
12772 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12773 sep,
12774 rb_str_subseq(str, rpos, RSTRING_LEN(str)-rpos));
12775 failed:
12776 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(rb_cString, str));
12777}
12778
12779/*
12780 * call-seq:
12781 * start_with?(*patterns) -> true or false
12782 *
12783 * :include: doc/string/start_with_p.rdoc
12784 *
12785 */
12786
12787static VALUE
12788rb_str_start_with(int argc, VALUE *argv, VALUE str)
12789{
12790 int i;
12791
12792 for (i=0; i<argc; i++) {
12793 VALUE tmp = argv[i];
12794 if (RB_TYPE_P(tmp, T_REGEXP)) {
12795 if (rb_reg_start_with_p(tmp, str))
12796 return Qtrue;
12797 }
12798 else {
12799 const char *p, *s, *e;
12800 rb_len_t slen, tlen;
12801 rb_encoding *enc;
12802
12803 StringValue(tmp);
12804 enc = rb_enc_check(str, tmp);
12805 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12806 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12807 p = RSTRING_PTR(str);
12808 e = p + slen;
12809 s = p + tlen;
12810 if (!at_char_right_boundary(p, s, e, enc))
12811 continue;
12812 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12813 return Qtrue;
12814 }
12815 }
12816 return Qfalse;
12817}
12818
12819/*
12820 * call-seq:
12821 * end_with?(*strings) -> true or false
12822 *
12823 * :include: doc/string/end_with_p.rdoc
12824 *
12825 */
12826
12827static VALUE
12828rb_str_end_with(int argc, VALUE *argv, VALUE str)
12829{
12830 int i;
12831
12832 for (i=0; i<argc; i++) {
12833 VALUE tmp = argv[i];
12834 const char *p, *s, *e;
12835 rb_len_t slen, tlen;
12836 rb_encoding *enc;
12837
12838 StringValue(tmp);
12839 enc = rb_enc_check(str, tmp);
12840 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12841 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12842 p = RSTRING_PTR(str);
12843 e = p + slen;
12844 s = e - tlen;
12845 if (!at_char_boundary(p, s, e, enc))
12846 continue;
12847 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12848 return Qtrue;
12849 }
12850 return Qfalse;
12851}
12852
12862static rb_len_t
12863deleted_prefix_length(VALUE str, VALUE prefix)
12864{
12865 const char *strptr, *prefixptr;
12866 rb_len_t olen, prefixlen;
12867 rb_encoding *enc = rb_enc_get(str);
12868
12869 StringValue(prefix);
12870
12871 if (!is_broken_string(prefix) ||
12872 !rb_enc_asciicompat(enc) ||
12873 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12874 enc = rb_enc_check(str, prefix);
12875 }
12876
12877 /* return 0 if not start with prefix */
12878 prefixlen = RSTRING_LEN(prefix);
12879 if (prefixlen <= 0) return 0;
12880 olen = RSTRING_LEN(str);
12881 if (olen < prefixlen) return 0;
12882 strptr = RSTRING_PTR(str);
12883 prefixptr = RSTRING_PTR(prefix);
12884 if (memcmp(strptr, prefixptr, prefixlen) != 0) return 0;
12885 if (is_broken_string(prefix)) {
12886 if (!is_broken_string(str)) {
12887 /* prefix in a valid string cannot be broken */
12888 return 0;
12889 }
12890 const char *strend = strptr + olen;
12891 const char *after_prefix = strptr + prefixlen;
12892 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12893 /* prefix does not end at char-boundary */
12894 return 0;
12895 }
12896 }
12897 /* prefix part in `str` also should be valid. */
12898
12899 return prefixlen;
12900}
12901
12902/*
12903 * call-seq:
12904 * delete_prefix!(prefix) -> self or nil
12905 *
12906 * Like String#delete_prefix, except that +self+ is modified in place;
12907 * returns +self+ if the prefix is removed, +nil+ otherwise.
12908 *
12909 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12910 */
12911
12912static VALUE
12913rb_str_delete_prefix_bang(VALUE str, VALUE prefix)
12914{
12915 rb_len_t prefixlen;
12916 str_modify_keep_cr(str);
12917
12918 prefixlen = deleted_prefix_length(str, prefix);
12919 if (prefixlen <= 0) return Qnil;
12920
12921 return rb_str_drop_bytes(str, prefixlen);
12922}
12923
12924/*
12925 * call-seq:
12926 * delete_prefix(prefix) -> new_string
12927 *
12928 * :include: doc/string/delete_prefix.rdoc
12929 *
12930 */
12931
12932static VALUE
12933rb_str_delete_prefix(VALUE str, VALUE prefix)
12934{
12935 rb_len_t prefixlen;
12936
12937 prefixlen = deleted_prefix_length(str, prefix);
12938 if (prefixlen <= 0) return str_duplicate(rb_cString, str);
12939
12940 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
12941}
12942
12952static rb_len_t
12953deleted_suffix_length(VALUE str, VALUE suffix)
12954{
12955 const char *strptr, *suffixptr;
12956 rb_len_t olen, suffixlen;
12957 rb_encoding *enc;
12958
12959 StringValue(suffix);
12960 if (is_broken_string(suffix)) return 0;
12961 enc = rb_enc_check(str, suffix);
12962
12963 /* return 0 if not start with suffix */
12964 suffixlen = RSTRING_LEN(suffix);
12965 if (suffixlen <= 0) return 0;
12966 olen = RSTRING_LEN(str);
12967 if (olen < suffixlen) return 0;
12968 strptr = RSTRING_PTR(str);
12969 suffixptr = RSTRING_PTR(suffix);
12970 const char *strend = strptr + olen;
12971 const char *before_suffix = strend - suffixlen;
12972 if (memcmp(before_suffix, suffixptr, suffixlen) != 0) return 0;
12973 if (!at_char_boundary(strptr, before_suffix, strend, enc)) return 0;
12974
12975 return suffixlen;
12976}
12977
12978/*
12979 * call-seq:
12980 * delete_suffix!(suffix) -> self or nil
12981 *
12982 * Like String#delete_suffix, except that +self+ is modified in place;
12983 * returns +self+ if the suffix is removed, +nil+ otherwise.
12984 *
12985 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12986 */
12987
12988static VALUE
12989rb_str_delete_suffix_bang(VALUE str, VALUE suffix)
12990{
12991 rb_len_t suffixlen;
12992 str_modifiable(str);
12993
12994 suffixlen = deleted_suffix_length(str, suffix);
12995 if (suffixlen <= 0) return Qnil;
12996
12997 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
12998}
12999
13000/*
13001 * call-seq:
13002 * delete_suffix(suffix) -> new_string
13003 *
13004 * :include: doc/string/delete_suffix.rdoc
13005 *
13006 */
13007
13008static VALUE
13009rb_str_delete_suffix(VALUE str, VALUE suffix)
13010{
13011 rb_len_t suffixlen;
13012
13013 suffixlen = deleted_suffix_length(str, suffix);
13014 if (suffixlen <= 0) return str_duplicate(rb_cString, str);
13015
13016 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
13017}
13018
13019void
13020rb_str_setter(VALUE val, ID id, VALUE *var)
13021{
13022 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING)) {
13023 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
13024 }
13025 *var = val;
13026}
13027
13028static void
13029nil_setter_warning(ID id)
13030{
13031 rb_warn_deprecated("non-nil '%"PRIsVALUE"'", NULL, rb_id2str(id));
13032}
13033
13034void
13035rb_deprecated_str_setter(VALUE val, ID id, VALUE *var)
13036{
13037 rb_str_setter(val, id, var);
13038 if (!NIL_P(*var)) {
13039 nil_setter_warning(id);
13040 }
13041}
13042
13043static void
13044rb_fs_setter(VALUE val, ID id, VALUE *var)
13045{
13046 val = rb_fs_check(val);
13047 if (!val) {
13048 rb_raise(rb_eTypeError,
13049 "value of %"PRIsVALUE" must be String or Regexp",
13050 rb_id2str(id));
13051 }
13052 if (!NIL_P(val)) {
13053 nil_setter_warning(id);
13054 }
13055 *var = val;
13056}
13057
13058
13059/*
13060 * call-seq:
13061 * force_encoding(encoding) -> self
13062 *
13063 * :include: doc/string/force_encoding.rdoc
13064 *
13065 */
13066
13067static VALUE
13068rb_str_force_encoding(VALUE str, VALUE enc)
13069{
13070 str_modifiable(str);
13071
13072 rb_encoding *encoding = rb_to_encoding(enc);
13073 int idx = rb_enc_to_index(encoding);
13074
13075 // If the encoding is unchanged, we do nothing.
13076 if (ENCODING_GET(str) == idx) {
13077 return str;
13078 }
13079
13080 rb_enc_associate_index(str, idx);
13081
13082 // If the coderange was 7bit and the new encoding is ASCII-compatible
13083 // we can keep the coderange.
13084 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT && encoding && rb_enc_asciicompat(encoding)) {
13085 return str;
13086 }
13087
13089 return str;
13090}
13091
13092/*
13093 * call-seq:
13094 * b -> new_string
13095 *
13096 * :include: doc/string/b.rdoc
13097 *
13098 */
13099
13100static VALUE
13101rb_str_b(VALUE str)
13102{
13103 VALUE str2;
13104 if (STR_EMBED_P(str)) {
13105 str2 = str_alloc_embed(rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13106 }
13107 else {
13108 str2 = str_alloc_heap(rb_cString);
13109 }
13110 str_replace_shared_without_enc(str2, str);
13111
13112 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13113 // BINARY strings can never be broken; they're either 7-bit ASCII or VALID.
13114 // If we know the receiver's code range then we know the result's code range.
13115 int cr = ENC_CODERANGE(str);
13116 switch (cr) {
13117 case ENC_CODERANGE_7BIT:
13119 break;
13123 break;
13124 default:
13125 ENC_CODERANGE_CLEAR(str2);
13126 break;
13127 }
13128 }
13129
13130 return str2;
13131}
13132
13133/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
13134static VALUE
13135rb_str_valid_encoding_p(VALUE str)
13136{
13137 int cr = rb_enc_str_coderange(str);
13138
13139 return RBOOL(cr != ENC_CODERANGE_BROKEN);
13140}
13141
13142/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
13143static VALUE
13144rb_str_is_ascii_only_p(VALUE str)
13145{
13146 int cr = rb_enc_str_coderange(str);
13147
13148 return RBOOL(cr == ENC_CODERANGE_7BIT);
13149}
13150
13151VALUE
13153{
13154 static const char ellipsis[] = "...";
13155 const rb_len_t ellipsislen = sizeof(ellipsis) - 1;
13156 rb_encoding *const enc = rb_enc_get(str);
13157 const rb_len_t blen = RSTRING_LEN(str);
13158 const char *const p = RSTRING_PTR(str), *e = p + blen;
13159 VALUE estr, ret = 0;
13160
13161 if (len < 0) rb_raise(rb_eIndexError, "negative length %"PRIdLEN, len);
13162 if (len * rb_enc_mbminlen(enc) >= blen ||
13163 (e = rb_enc_nth(p, e, len, enc)) - p == blen) {
13164 ret = str;
13165 }
13166 else if (len <= ellipsislen ||
13167 !(e = rb_enc_step_back(p, e, e, len = ellipsislen, enc))) {
13168 if (rb_enc_asciicompat(enc)) {
13169 ret = rb_str_new(ellipsis, len);
13170 rb_enc_associate(ret, enc);
13171 }
13172 else {
13173 estr = rb_usascii_str_new(ellipsis, len);
13174 ret = rb_str_encode(estr, rb_enc_from_encoding(enc), 0, Qnil);
13175 }
13176 }
13177 else if (ret = rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13178 rb_str_cat(ret, ellipsis, ellipsislen);
13179 }
13180 else {
13181 estr = rb_str_encode(rb_usascii_str_new(ellipsis, ellipsislen),
13182 rb_enc_from_encoding(enc), 0, Qnil);
13183 rb_str_append(ret, estr);
13184 }
13185 return ret;
13186}
13187
13188static VALUE
13189str_compat_and_valid(VALUE str, rb_encoding *enc)
13190{
13191 int cr;
13192 str = StringValue(str);
13193 cr = rb_enc_str_coderange(str);
13194 if (cr == ENC_CODERANGE_BROKEN) {
13195 rb_raise(rb_eArgError, "replacement must be valid byte sequence '%+"PRIsVALUE"'", str);
13196 }
13197 else {
13198 rb_encoding *e = STR_ENC_GET(str);
13199 if (cr == ENC_CODERANGE_7BIT ? rb_enc_mbminlen(enc) != 1 : enc != e) {
13200 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
13201 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13202 }
13203 }
13204 return str;
13205}
13206
13207static VALUE enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr);
13208
13209VALUE
13211{
13212 rb_encoding *enc = STR_ENC_GET(str);
13213 return enc_str_scrub(enc, str, repl, ENC_CODERANGE(str));
13214}
13215
13216VALUE
13217rb_enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl)
13218{
13219 int cr = ENC_CODERANGE_UNKNOWN;
13220 if (enc == STR_ENC_GET(str)) {
13221 /* cached coderange makes sense only when enc equals the
13222 * actual encoding of str */
13223 cr = ENC_CODERANGE(str);
13224 }
13225 return enc_str_scrub(enc, str, repl, cr);
13226}
13227
13228static VALUE
13229enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
13230{
13231 int encidx;
13232 VALUE buf = Qnil;
13233 const char *rep, *p, *e, *p1, *sp;
13234 rb_len_t replen = -1;
13235 rb_len_t slen;
13236
13237 if (rb_block_given_p()) {
13238 if (!NIL_P(repl))
13239 rb_raise(rb_eArgError, "both of block and replacement given");
13240 replen = 0;
13241 }
13242
13243 if (ENC_CODERANGE_CLEAN_P(cr))
13244 return Qnil;
13245
13246 if (!NIL_P(repl)) {
13247 repl = str_compat_and_valid(repl, enc);
13248 }
13249
13250 if (rb_enc_dummy_p(enc)) {
13251 return Qnil;
13252 }
13253 encidx = rb_enc_to_index(enc);
13254
13255#define DEFAULT_REPLACE_CHAR(str) do { \
13256 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13257 rep = replace; replen = (int)sizeof(replace); \
13258 } while (0)
13259
13260 slen = RSTRING_LEN(str);
13261 p = RSTRING_PTR(str);
13262 e = RSTRING_END(str);
13263 p1 = p;
13264 sp = p;
13265
13266 if (rb_enc_asciicompat(enc)) {
13267 int rep7bit_p;
13268 if (!replen) {
13269 rep = NULL;
13270 rep7bit_p = FALSE;
13271 }
13272 else if (!NIL_P(repl)) {
13273 rep = RSTRING_PTR(repl);
13274 replen = RSTRING_LEN(repl);
13275 rep7bit_p = (ENC_CODERANGE(repl) == ENC_CODERANGE_7BIT);
13276 }
13277 else if (encidx == rb_utf8_encindex()) {
13278 DEFAULT_REPLACE_CHAR("\xEF\xBF\xBD");
13279 rep7bit_p = FALSE;
13280 }
13281 else {
13282 DEFAULT_REPLACE_CHAR("?");
13283 rep7bit_p = TRUE;
13284 }
13285 cr = ENC_CODERANGE_7BIT;
13286
13287 p = search_nonascii(p, e);
13288 if (!p) {
13289 p = e;
13290 }
13291 while (p < e) {
13292 int ret = rb_enc_precise_mbclen(p, e, enc);
13293 if (MBCLEN_NEEDMORE_P(ret)) {
13294 break;
13295 }
13296 else if (MBCLEN_CHARFOUND_P(ret)) {
13298 p += MBCLEN_CHARFOUND_LEN(ret);
13299 /* After a multibyte character, fast-skip the following ASCII run. */
13300 p = search_nonascii(p, e);
13301 if (!p) {
13302 p = e;
13303 break;
13304 }
13305 }
13306 else if (MBCLEN_INVALID_P(ret)) {
13307 /*
13308 * p1~p: valid ascii/multibyte chars
13309 * p ~e: invalid bytes + unknown bytes
13310 */
13311 rb_len_t clen = rb_enc_mbmaxlen(enc);
13312 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
13313 if (p > p1) {
13314 rb_str_buf_cat(buf, p1, p - p1);
13315 }
13316
13317 if (e - p < clen) clen = e - p;
13318 if (clen <= 2) {
13319 clen = 1;
13320 }
13321 else {
13322 const char *q = p;
13323 clen--;
13324 for (; clen > 1; clen--) {
13325 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13326 if (MBCLEN_NEEDMORE_P(ret)) break;
13327 if (MBCLEN_INVALID_P(ret)) continue;
13329 }
13330 }
13331 if (rep) {
13332 rb_str_buf_cat(buf, rep, replen);
13333 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
13334 }
13335 else {
13336 repl = rb_yield(rb_enc_str_new(p, clen, enc));
13337 str_mod_check(str, sp, slen);
13338 repl = str_compat_and_valid(repl, enc);
13339 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13342 }
13343 p += clen;
13344 p1 = p;
13345 p = search_nonascii(p, e);
13346 if (!p) {
13347 p = e;
13348 break;
13349 }
13350 }
13351 else {
13353 }
13354 }
13355 if (NIL_P(buf)) {
13356 if (p == e) {
13357 ENC_CODERANGE_SET(str, cr);
13358 return Qnil;
13359 }
13360 buf = rb_str_buf_new(RSTRING_LEN(str));
13361 }
13362 if (p1 < p) {
13363 rb_str_buf_cat(buf, p1, p - p1);
13364 }
13365 if (p < e) {
13366 if (rep) {
13367 rb_str_buf_cat(buf, rep, replen);
13368 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
13369 }
13370 else {
13371 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
13372 str_mod_check(str, sp, slen);
13373 repl = str_compat_and_valid(repl, enc);
13374 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13377 }
13378 }
13379 }
13380 else {
13381 /* ASCII incompatible */
13382 rb_len_t mbminlen = rb_enc_mbminlen(enc);
13383 if (!replen) {
13384 rep = NULL;
13385 }
13386 else if (!NIL_P(repl)) {
13387 rep = RSTRING_PTR(repl);
13388 replen = RSTRING_LEN(repl);
13389 }
13390 else if (encidx == ENCINDEX_UTF_16BE) {
13391 DEFAULT_REPLACE_CHAR("\xFF\xFD");
13392 }
13393 else if (encidx == ENCINDEX_UTF_16LE) {
13394 DEFAULT_REPLACE_CHAR("\xFD\xFF");
13395 }
13396 else if (encidx == ENCINDEX_UTF_32BE) {
13397 DEFAULT_REPLACE_CHAR("\x00\x00\xFF\xFD");
13398 }
13399 else if (encidx == ENCINDEX_UTF_32LE) {
13400 DEFAULT_REPLACE_CHAR("\xFD\xFF\x00\x00");
13401 }
13402 else {
13403 DEFAULT_REPLACE_CHAR("?");
13404 }
13405
13406 while (p < e) {
13407 int ret = rb_enc_precise_mbclen(p, e, enc);
13408 if (MBCLEN_NEEDMORE_P(ret)) {
13409 break;
13410 }
13411 else if (MBCLEN_CHARFOUND_P(ret)) {
13412 p += MBCLEN_CHARFOUND_LEN(ret);
13413 }
13414 else if (MBCLEN_INVALID_P(ret)) {
13415 const char *q = p;
13416 rb_len_t clen = rb_enc_mbmaxlen(enc);
13417 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
13418 if (p > p1) rb_str_buf_cat(buf, p1, p - p1);
13419
13420 if (e - p < clen) clen = e - p;
13421 if (clen <= mbminlen * 2) {
13422 clen = mbminlen;
13423 }
13424 else {
13425 clen -= mbminlen;
13426 for (; clen > mbminlen; clen-=mbminlen) {
13427 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13428 if (MBCLEN_NEEDMORE_P(ret)) break;
13429 if (MBCLEN_INVALID_P(ret)) continue;
13431 }
13432 }
13433 if (rep) {
13434 rb_str_buf_cat(buf, rep, replen);
13435 }
13436 else {
13437 repl = rb_yield(rb_enc_str_new(p, clen, enc));
13438 str_mod_check(str, sp, slen);
13439 repl = str_compat_and_valid(repl, enc);
13440 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13441 }
13442 p += clen;
13443 p1 = p;
13444 }
13445 else {
13447 }
13448 }
13449 if (NIL_P(buf)) {
13450 if (p == e) {
13452 return Qnil;
13453 }
13454 buf = rb_str_buf_new(RSTRING_LEN(str));
13455 }
13456 if (p1 < p) {
13457 rb_str_buf_cat(buf, p1, p - p1);
13458 }
13459 if (p < e) {
13460 if (rep) {
13461 rb_str_buf_cat(buf, rep, replen);
13462 }
13463 else {
13464 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
13465 str_mod_check(str, sp, slen);
13466 repl = str_compat_and_valid(repl, enc);
13467 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13468 }
13469 }
13471 }
13472 ENCODING_CODERANGE_SET(buf, rb_enc_to_index(enc), cr);
13473 return buf;
13474}
13475
13476/*
13477 * call-seq:
13478 * scrub(replacement_string = default_replacement_string) -> new_string
13479 * scrub{|sequence| ... } -> new_string
13480 *
13481 * :include: doc/string/scrub.rdoc
13482 *
13483 */
13484static VALUE
13485str_scrub(int argc, VALUE *argv, VALUE str)
13486{
13487 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13488 VALUE new = rb_str_scrub(str, repl);
13489 return NIL_P(new) ? str_duplicate(rb_cString, str): new;
13490}
13491
13492/*
13493 * call-seq:
13494 * scrub!(replacement_string = default_replacement_string) -> self
13495 * scrub!{|sequence| ... } -> self
13496 *
13497 * Like String#scrub, except that:
13498 *
13499 * - Any replacements are made in +self+.
13500 * - Returns +self+.
13501 *
13502 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13503 *
13504 */
13505static VALUE
13506str_scrub_bang(int argc, VALUE *argv, VALUE str)
13507{
13508 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13509 VALUE new = rb_str_scrub(str, repl);
13510 if (!NIL_P(new)) rb_str_replace(str, new);
13511 return str;
13512}
13513
13514static ID id_normalize;
13515static ID id_normalized_p;
13516static VALUE mUnicodeNormalize;
13517
13518static VALUE
13519unicode_normalize_common(int argc, VALUE *argv, VALUE str, ID id)
13520{
13521 static int UnicodeNormalizeRequired = 0;
13522 VALUE argv2[2];
13523
13524 if (!UnicodeNormalizeRequired) {
13525 rb_require("unicode_normalize/normalize.rb");
13526 UnicodeNormalizeRequired = 1;
13527 }
13528 argv2[0] = str;
13529 if (rb_check_arity(argc, 0, 1)) argv2[1] = argv[0];
13530 return rb_funcallv(mUnicodeNormalize, id, argc+1, argv2);
13531}
13532
13533/*
13534 * call-seq:
13535 * unicode_normalize(form = :nfc) -> string
13536 *
13537 * :include: doc/string/unicode_normalize.rdoc
13538 *
13539 */
13540static VALUE
13541rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
13542{
13543 return unicode_normalize_common(argc, argv, str, id_normalize);
13544}
13545
13546/*
13547 * call-seq:
13548 * unicode_normalize!(form = :nfc) -> self
13549 *
13550 * Like String#unicode_normalize, except that the normalization
13551 * is performed on +self+ (not on a copy of +self+).
13552 *
13553 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13554 *
13555 */
13556static VALUE
13557rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
13558{
13559 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13560}
13561
13562/* call-seq:
13563 * unicode_normalized?(form = :nfc) -> true or false
13564 *
13565 * Returns whether +self+ is in the given +form+ of Unicode normalization;
13566 * see String#unicode_normalize.
13567 *
13568 * The +form+ must be one of +:nfc+, +:nfd+, +:nfkc+, or +:nfkd+.
13569 *
13570 * Examples:
13571 *
13572 * "a\u0300".unicode_normalized? # => false
13573 * "a\u0300".unicode_normalized?(:nfd) # => true
13574 * "\u00E0".unicode_normalized? # => true
13575 * "\u00E0".unicode_normalized?(:nfd) # => false
13576 *
13577 *
13578 * Raises an exception if +self+ is not in a Unicode encoding:
13579 *
13580 * s = "\xE0".force_encoding(Encoding::ISO_8859_1)
13581 * s.unicode_normalized? # Raises Encoding::CompatibilityError
13582 *
13583 * Related: see {Querying}[rdoc-ref:String@Querying].
13584 */
13585static VALUE
13586rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
13587{
13588 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13589}
13590
13591/**********************************************************************
13592 * Document-class: Symbol
13593 *
13594 * A +Symbol+ object represents a named identifier inside the Ruby interpreter.
13595 *
13596 * You can create a +Symbol+ object explicitly with:
13597 *
13598 * - A {symbol literal}[rdoc-ref:syntax/literals.rdoc@Symbol+Literals].
13599 *
13600 * The same +Symbol+ object will be
13601 * created for a given name or string for the duration of a program's
13602 * execution, regardless of the context or meaning of that name. Thus
13603 * if <code>Fred</code> is a constant in one context, a method in
13604 * another, and a class in a third, the +Symbol+ <code>:Fred</code>
13605 * will be the same object in all three contexts.
13606 *
13607 * module One
13608 * class Fred
13609 * end
13610 * $f1 = :Fred
13611 * end
13612 * module Two
13613 * Fred = 1
13614 * $f2 = :Fred
13615 * end
13616 * def Fred()
13617 * end
13618 * $f3 = :Fred
13619 * $f1.object_id #=> 2514190
13620 * $f2.object_id #=> 2514190
13621 * $f3.object_id #=> 2514190
13622 *
13623 * Constant, method, and variable names are returned as symbols:
13624 *
13625 * module One
13626 * Two = 2
13627 * def three; 3 end
13628 * @four = 4
13629 * @@five = 5
13630 * $six = 6
13631 * end
13632 * seven = 7
13633 *
13634 * One.constants
13635 * # => [:Two]
13636 * One.instance_methods(true)
13637 * # => [:three]
13638 * One.instance_variables
13639 * # => [:@four]
13640 * One.class_variables
13641 * # => [:@@five]
13642 * global_variables.grep(/six/)
13643 * # => [:$six]
13644 * local_variables
13645 * # => [:seven]
13646 *
13647 * A +Symbol+ object differs from a String object in that
13648 * a +Symbol+ object represents an identifier, while a String object
13649 * represents text or data.
13650 *
13651 * == What's Here
13652 *
13653 * First, what's elsewhere. Class +Symbol+:
13654 *
13655 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
13656 * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
13657 *
13658 * Here, class +Symbol+ provides methods that are useful for:
13659 *
13660 * - {Querying}[rdoc-ref:Symbol@Methods+for+Querying]
13661 * - {Comparing}[rdoc-ref:Symbol@Methods+for+Comparing]
13662 * - {Converting}[rdoc-ref:Symbol@Methods+for+Converting]
13663 *
13664 * === Methods for Querying
13665 *
13666 * - ::all_symbols: Returns an array of the symbols currently in Ruby's symbol table.
13667 * - #=~: Returns the index of the first substring in symbol that matches a
13668 * given Regexp or other object; returns +nil+ if no match is found.
13669 * - #[], #slice : Returns a substring of symbol
13670 * determined by a given index, start/length, or range, or string.
13671 * - #empty?: Returns +true+ if +self.length+ is zero; +false+ otherwise.
13672 * - #encoding: Returns the Encoding object that represents the encoding
13673 * of symbol.
13674 * - #end_with?: Returns +true+ if symbol ends with
13675 * any of the given strings.
13676 * - #match: Returns a MatchData object if symbol
13677 * matches a given Regexp; +nil+ otherwise.
13678 * - #match?: Returns +true+ if symbol
13679 * matches a given Regexp; +false+ otherwise.
13680 * - #length, #size: Returns the number of characters in symbol.
13681 * - #start_with?: Returns +true+ if symbol starts with
13682 * any of the given strings.
13683 *
13684 * === Methods for Comparing
13685 *
13686 * - #<=>: Returns -1, 0, or 1 as a given symbol is smaller than, equal to,
13687 * or larger than symbol.
13688 * - #==, #===: Returns +true+ if a given symbol has the same content and
13689 * encoding.
13690 * - #casecmp: Ignoring case, returns -1, 0, or 1 as a given
13691 * symbol is smaller than, equal to, or larger than symbol.
13692 * - #casecmp?: Returns +true+ if symbol is equal to a given symbol
13693 * after Unicode case folding; +false+ otherwise.
13694 *
13695 * === Methods for Converting
13696 *
13697 * - #capitalize: Returns symbol with the first character upcased
13698 * and all other characters downcased.
13699 * - #downcase: Returns symbol with all characters downcased.
13700 * - #inspect: Returns the string representation of +self+ as a symbol literal.
13701 * - #name: Returns the frozen string corresponding to symbol.
13702 * - #succ, #next: Returns the symbol that is the successor to symbol.
13703 * - #swapcase: Returns symbol with all upcase characters downcased
13704 * and all downcase characters upcased.
13705 * - #to_proc: Returns a Proc object which responds to the method named by symbol.
13706 * - #to_s, #id2name: Returns the string corresponding to +self+.
13707 * - #to_sym, #intern: Returns +self+.
13708 * - #upcase: Returns symbol with all characters upcased.
13709 *
13710 */
13711
13712
13713/*
13714 * call-seq:
13715 * self == other -> true or false
13716 *
13717 * Returns whether +other+ is the same object as +self+.
13718 */
13719
13720#define sym_equal rb_obj_equal
13721
13722static int
13723sym_printable(const char *s, const char *send, rb_encoding *enc)
13724{
13725 while (s < send) {
13726 int n;
13727 int c = rb_enc_precise_mbclen(s, send, enc);
13728
13729 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
13730 n = MBCLEN_CHARFOUND_LEN(c);
13731 c = rb_enc_mbc_to_codepoint(s, send, enc);
13732 if (!rb_enc_isprint(c, enc)) return FALSE;
13733 s += n;
13734 }
13735 return TRUE;
13736}
13737
13738int
13739rb_str_symname_p(VALUE sym)
13740{
13741 rb_encoding *enc;
13742 const char *ptr;
13743 rb_len_t len;
13744 rb_encoding *resenc = rb_default_internal_encoding();
13745
13746 if (resenc == NULL) resenc = rb_default_external_encoding();
13747 enc = STR_ENC_GET(sym);
13748 ptr = RSTRING_PTR(sym);
13749 len = RSTRING_LEN(sym);
13750 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) || len != (rb_len_t)strlen(ptr) ||
13751 !rb_enc_symname2_p(ptr, len, enc) || !sym_printable(ptr, ptr + len, enc)) {
13752 return FALSE;
13753 }
13754 return TRUE;
13755}
13756
13757VALUE
13758rb_str_quote_unprintable(VALUE str)
13759{
13760 rb_encoding *enc;
13761 const char *ptr;
13762 rb_len_t len;
13763 rb_encoding *resenc;
13764
13765 Check_Type(str, T_STRING);
13766 resenc = rb_default_internal_encoding();
13767 if (resenc == NULL) resenc = rb_default_external_encoding();
13768 enc = STR_ENC_GET(str);
13769 ptr = RSTRING_PTR(str);
13770 len = RSTRING_LEN(str);
13771 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13772 !sym_printable(ptr, ptr + len, enc)) {
13773 return rb_str_escape(str);
13774 }
13775 return str;
13776}
13777
13778VALUE
13779rb_id_quote_unprintable(ID id)
13780{
13781 VALUE str = rb_id2str(id);
13782 if (!rb_str_symname_p(str)) {
13783 return rb_str_escape(str);
13784 }
13785 return str;
13786}
13787
13788/*
13789 * call-seq:
13790 * inspect -> string
13791 *
13792 * Returns a string representation of +self+ (including the leading colon):
13793 *
13794 * :foo.inspect # => ":foo"
13795 *
13796 * Related: Symbol#to_s, Symbol#name.
13797 *
13798 */
13799
13800static VALUE
13801sym_inspect(VALUE sym)
13802{
13803 VALUE str = rb_sym2str(sym);
13804 const char *ptr;
13805 rb_len_t len;
13806 char *dest;
13807
13808 if (!rb_str_symname_p(str)) {
13809 str = rb_str_inspect(str);
13810 len = RSTRING_LEN(str);
13811 rb_str_resize(str, len + 1);
13812 dest = RSTRING_PTR(str);
13813 memmove(dest + 1, dest, len);
13814 }
13815 else {
13816 rb_encoding *enc = STR_ENC_GET(str);
13817 VALUE orig_str = str;
13818
13819 len = RSTRING_LEN(orig_str);
13820 str = rb_enc_str_new(0, len + 1, enc);
13821
13822 // Get data pointer after allocation
13823 ptr = RSTRING_PTR(orig_str);
13824 dest = RSTRING_PTR(str);
13825 memcpy(dest + 1, ptr, len);
13826
13827 RB_GC_GUARD(orig_str);
13828 }
13829 dest[0] = ':';
13830
13832
13833 return str;
13834}
13835
13836VALUE
13838{
13839 return rb_sym2str(sym);
13840}
13841
13842VALUE
13843rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc)
13844{
13845 VALUE obj;
13846
13847 if (argc < 1) {
13848 rb_raise(rb_eArgError, "no receiver given");
13849 }
13850 obj = argv[0];
13851 return rb_funcall_with_block_kw(obj, mid, argc - 1, argv + 1, passed_proc, kw_splat);
13852}
13853
13854/*
13855 * call-seq:
13856 * succ
13857 *
13858 * Equivalent to <tt>self.to_s.succ.to_sym</tt>:
13859 *
13860 * :foo.succ # => :fop
13861 *
13862 * Related: String#succ.
13863 */
13864
13865static VALUE
13866sym_succ(VALUE sym)
13867{
13868 return rb_str_intern(rb_str_succ(rb_sym2str(sym)));
13869}
13870
13871/*
13872 * call-seq:
13873 * self <=> other -> -1, 0, 1, or nil
13874 *
13875 * Compares +self+ and +other+, using String#<=>.
13876 *
13877 * Returns:
13878 *
13879 * - <tt>self.to_s <=> other.to_s</tt>, if +other+ is a symbol.
13880 * - +nil+, otherwise.
13881 *
13882 * Examples:
13883 *
13884 * :bar <=> :foo # => -1
13885 * :foo <=> :foo # => 0
13886 * :foo <=> :bar # => 1
13887 * :foo <=> 'bar' # => nil
13888 *
13889 * \Class \Symbol includes module Comparable,
13890 * each of whose methods uses Symbol#<=> for comparison.
13891 *
13892 * Related: String#<=>.
13893 */
13894
13895static VALUE
13896sym_cmp(VALUE sym, VALUE other)
13897{
13898 if (!SYMBOL_P(other)) {
13899 return Qnil;
13900 }
13901 return rb_str_cmp_m(rb_sym2str(sym), rb_sym2str(other));
13902}
13903
13904/*
13905 * call-seq:
13906 * casecmp(object) -> -1, 0, 1, or nil
13907 *
13908 * :include: doc/symbol/casecmp.rdoc
13909 *
13910 */
13911
13912static VALUE
13913sym_casecmp(VALUE sym, VALUE other)
13914{
13915 if (!SYMBOL_P(other)) {
13916 return Qnil;
13917 }
13918 return str_casecmp(rb_sym2str(sym), rb_sym2str(other));
13919}
13920
13921/*
13922 * call-seq:
13923 * casecmp?(object) -> true, false, or nil
13924 *
13925 * :include: doc/symbol/casecmp_p.rdoc
13926 *
13927 */
13928
13929static VALUE
13930sym_casecmp_p(VALUE sym, VALUE other)
13931{
13932 if (!SYMBOL_P(other)) {
13933 return Qnil;
13934 }
13935 return str_casecmp_p(rb_sym2str(sym), rb_sym2str(other));
13936}
13937
13938/*
13939 * call-seq:
13940 * self =~ other -> integer or nil
13941 *
13942 * Equivalent to <tt>self.to_s =~ other</tt>,
13943 * including possible updates to global variables;
13944 * see String#=~.
13945 *
13946 */
13947
13948static VALUE
13949sym_match(VALUE sym, VALUE other)
13950{
13951 return rb_str_match(rb_sym2str(sym), other);
13952}
13953
13954/*
13955 * call-seq:
13956 * match(pattern, offset = 0) -> matchdata or nil
13957 * match(pattern, offset = 0) {|matchdata| } -> object
13958 *
13959 * Equivalent to <tt>self.to_s.match</tt>,
13960 * including possible updates to global variables;
13961 * see String#match.
13962 *
13963 */
13964
13965static VALUE
13966sym_match_m(int argc, VALUE *argv, VALUE sym)
13967{
13968 return rb_str_match_m(argc, argv, rb_sym2str(sym));
13969}
13970
13971/*
13972 * call-seq:
13973 * match?(pattern, offset) -> true or false
13974 *
13975 * Equivalent to <tt>sym.to_s.match?</tt>;
13976 * see String#match.
13977 *
13978 */
13979
13980static VALUE
13981sym_match_m_p(int argc, VALUE *argv, VALUE sym)
13982{
13983 return rb_str_match_m_p(argc, argv, sym);
13984}
13985
13986/*
13987 * call-seq:
13988 * self[offset] -> string or nil
13989 * self[offset, size] -> string or nil
13990 * self[range] -> string or nil
13991 * self[regexp, capture = 0] -> string or nil
13992 * self[substring] -> string or nil
13993 *
13994 * Equivalent to <tt>symbol.to_s[]</tt>; see String#[].
13995 *
13996 */
13997
13998static VALUE
13999sym_aref(int argc, VALUE *argv, VALUE sym)
14000{
14001 return rb_str_aref_m(argc, argv, rb_sym2str(sym));
14002}
14003
14004/*
14005 * call-seq:
14006 * length -> integer
14007 *
14008 * Equivalent to <tt>self.to_s.length</tt>; see String#length.
14009 */
14010
14011static VALUE
14012sym_length(VALUE sym)
14013{
14014 return rb_str_length(rb_sym2str(sym));
14015}
14016
14017/*
14018 * call-seq:
14019 * upcase(mapping) -> symbol
14020 *
14021 * Equivalent to <tt>sym.to_s.upcase.to_sym</tt>.
14022 *
14023 * See String#upcase.
14024 *
14025 */
14026
14027static VALUE
14028sym_upcase(int argc, VALUE *argv, VALUE sym)
14029{
14030 return rb_str_intern(rb_str_upcase(argc, argv, rb_sym2str(sym)));
14031}
14032
14033/*
14034 * call-seq:
14035 * downcase(mapping) -> symbol
14036 *
14037 * Equivalent to <tt>sym.to_s.downcase.to_sym</tt>.
14038 *
14039 * See String#downcase.
14040 *
14041 * Related: Symbol#upcase.
14042 *
14043 */
14044
14045static VALUE
14046sym_downcase(int argc, VALUE *argv, VALUE sym)
14047{
14048 return rb_str_intern(rb_str_downcase(argc, argv, rb_sym2str(sym)));
14049}
14050
14051/*
14052 * call-seq:
14053 * capitalize(mapping) -> symbol
14054 *
14055 * Equivalent to <tt>sym.to_s.capitalize.to_sym</tt>.
14056 *
14057 * See String#capitalize.
14058 *
14059 */
14060
14061static VALUE
14062sym_capitalize(int argc, VALUE *argv, VALUE sym)
14063{
14064 return rb_str_intern(rb_str_capitalize(argc, argv, rb_sym2str(sym)));
14065}
14066
14067/*
14068 * call-seq:
14069 * swapcase(mapping) -> symbol
14070 *
14071 * Equivalent to <tt>sym.to_s.swapcase.to_sym</tt>.
14072 *
14073 * See String#swapcase.
14074 *
14075 */
14076
14077static VALUE
14078sym_swapcase(int argc, VALUE *argv, VALUE sym)
14079{
14080 return rb_str_intern(rb_str_swapcase(argc, argv, rb_sym2str(sym)));
14081}
14082
14083/*
14084 * call-seq:
14085 * start_with?(*string_or_regexp) -> true or false
14086 *
14087 * Equivalent to <tt>self.to_s.start_with?</tt>; see String#start_with?.
14088 *
14089 */
14090
14091static VALUE
14092sym_start_with(int argc, VALUE *argv, VALUE sym)
14093{
14094 return rb_str_start_with(argc, argv, rb_sym2str(sym));
14095}
14096
14097/*
14098 * call-seq:
14099 * end_with?(*strings) -> true or false
14100 *
14101 *
14102 * Equivalent to <tt>self.to_s.end_with?</tt>; see String#end_with?.
14103 *
14104 */
14105
14106static VALUE
14107sym_end_with(int argc, VALUE *argv, VALUE sym)
14108{
14109 return rb_str_end_with(argc, argv, rb_sym2str(sym));
14110}
14111
14112/*
14113 * call-seq:
14114 * encoding -> encoding
14115 *
14116 * Equivalent to <tt>self.to_s.encoding</tt>; see String#encoding.
14117 *
14118 */
14119
14120static VALUE
14121sym_encoding(VALUE sym)
14122{
14123 return rb_obj_encoding(rb_sym2str(sym));
14124}
14125
14126static VALUE
14127string_for_symbol(VALUE name)
14128{
14129 if (!RB_TYPE_P(name, T_STRING)) {
14130 VALUE tmp = rb_check_string_type(name);
14131 if (NIL_P(tmp)) {
14132 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
14133 name);
14134 }
14135 name = tmp;
14136 }
14137 return name;
14138}
14139
14140ID
14142{
14143 if (SYMBOL_P(name)) {
14144 return SYM2ID(name);
14145 }
14146 name = string_for_symbol(name);
14147 return rb_intern_str(name);
14148}
14149
14150VALUE
14152{
14153 if (SYMBOL_P(name)) {
14154 return name;
14155 }
14156 name = string_for_symbol(name);
14157 return rb_str_intern(name);
14158}
14159
14160/*
14161 * call-seq:
14162 * Symbol.all_symbols -> array_of_symbols
14163 *
14164 * Returns an array of all symbols currently in Ruby's symbol table:
14165 *
14166 * Symbol.all_symbols.size # => 9334
14167 * Symbol.all_symbols.take(3) # => [:!, :"\"", :"#"]
14168 *
14169 */
14170
14171static VALUE
14172sym_all_symbols(VALUE _)
14173{
14174 return rb_sym_all_symbols();
14175}
14176
14177VALUE
14178rb_str_to_interned_str(VALUE str)
14179{
14180 return rb_fstring(str);
14181}
14182
14183VALUE
14185{
14186 struct RString fake_str = {RBASIC_INIT};
14187 int encidx = ENCINDEX_US_ASCII;
14188 int coderange = ENC_CODERANGE_7BIT;
14189 if (len > 0 && search_nonascii(ptr, ptr + len)) {
14190 encidx = ENCINDEX_ASCII_8BIT;
14191 coderange = ENC_CODERANGE_VALID;
14192 }
14193 VALUE str = setup_fake_str(&fake_str, ptr, len, encidx);
14194 ENC_CODERANGE_SET(str, coderange);
14195 return register_fstring(str, true, false);
14196}
14197
14198VALUE
14200{
14201 return rb_interned_str(ptr, strlen(ptr));
14202}
14203
14204VALUE
14206{
14207 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14208 rb_enc_autoload(enc);
14209 }
14210
14211 struct RString fake_str = {RBASIC_INIT};
14212 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, false);
14213}
14214
14215VALUE
14216rb_enc_literal_str(const char *ptr, rb_len_t len, rb_encoding *enc)
14217{
14218 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14219 rb_enc_autoload(enc);
14220 }
14221
14222 struct RString fake_str = {RBASIC_INIT};
14223 VALUE str = register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true);
14224 RUBY_ASSERT(RB_OBJ_SHAREABLE_P(str) && (rb_gc_verify_shareable(str), 1));
14225 return str;
14226}
14227
14228VALUE
14230{
14231 return rb_enc_interned_str(ptr, strlen(ptr), enc);
14232}
14233
14234#if USE_YJIT || USE_ZJIT
14235void
14236rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint)
14237{
14238 if (RB_LIKELY(ENCODING_GET_INLINED(str) == rb_ascii8bit_encindex())) {
14239 ssize_t code = RB_NUM2SSIZE(codepoint);
14240
14241 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14242 rb_str_buf_cat_byte(str, (char) code);
14243 return;
14244 }
14245 }
14246
14247 rb_str_concat(str, codepoint);
14248}
14249#endif
14250
14251static int
14252fstring_set_class_i(VALUE *str, void *data)
14253{
14254 RBASIC_SET_CLASS(*str, rb_cString);
14255
14256 return ST_CONTINUE;
14257}
14258
14259void
14260Init_String(void)
14261{
14262 rb_cString = rb_define_class("String", rb_cObject);
14263
14264 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14265
14267 rb_define_alloc_func(rb_cString, empty_str_alloc);
14268 rb_define_singleton_method(rb_cString, "new", rb_str_s_new, -1);
14269 rb_define_singleton_method(rb_cString, "try_convert", rb_str_s_try_convert, 1);
14270 rb_define_method(rb_cString, "initialize", rb_str_init, -1);
14272 rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1);
14273 rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
14276 rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
14277 rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
14278 rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
14279 rb_define_method(rb_cString, "casecmp?", rb_str_casecmp_p, 1);
14282 rb_define_method(rb_cString, "%", rb_str_format_m, 1);
14283 rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
14284 rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
14285 rb_define_method(rb_cString, "insert", rb_str_insert, 2);
14288 rb_define_method(rb_cString, "bytesize", rb_str_bytesize, 0);
14289 rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
14290 rb_define_method(rb_cString, "=~", rb_str_match, 1);
14291 rb_define_method(rb_cString, "match", rb_str_match_m, -1);
14292 rb_define_method(rb_cString, "match?", rb_str_match_m_p, -1);
14294 rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0);
14296 rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0);
14297 rb_define_method(rb_cString, "upto", rb_str_upto, -1);
14298 rb_define_method(rb_cString, "index", rb_str_index_m, -1);
14299 rb_define_method(rb_cString, "byteindex", rb_str_byteindex_m, -1);
14300 rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1);
14301 rb_define_method(rb_cString, "byterindex", rb_str_byterindex_m, -1);
14302 rb_define_method(rb_cString, "clear", rb_str_clear, 0);
14303 rb_define_method(rb_cString, "chr", rb_str_chr, 0);
14304 rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
14305 rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);
14306 rb_define_method(rb_cString, "bit_get", rb_str_bit_get, -1);
14307 rb_define_method(rb_cString, "bit_set?", rb_str_bit_set_p, -1);
14308 rb_define_method(rb_cString, "bit_set", rb_str_bit_set, -1);
14309 rb_define_method(rb_cString, "bit_clear", rb_str_bit_clear, -1);
14310 rb_define_method(rb_cString, "bit_flip", rb_str_bit_flip, -1);
14311 rb_define_method(rb_cString, "bit_count", rb_str_bit_count, -1);
14312 rb_define_method(rb_cString, "bitwise_not", rb_str_bitwise_not, 0);
14313 rb_define_method(rb_cString, "bitwise_not!", rb_str_bitwise_not_bang, 0);
14314 rb_define_method(rb_cString, "bitwise_and", rb_str_bitwise_and, 1);
14315 rb_define_method(rb_cString, "bitwise_and!", rb_str_bitwise_and_bang, 1);
14316 rb_define_method(rb_cString, "bitwise_or", rb_str_bitwise_or, 1);
14317 rb_define_method(rb_cString, "bitwise_or!", rb_str_bitwise_or_bang, 1);
14318 rb_define_method(rb_cString, "bitwise_xor", rb_str_bitwise_xor, 1);
14319 rb_define_method(rb_cString, "bitwise_xor!", rb_str_bitwise_xor_bang, 1);
14320 rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);
14321 rb_define_method(rb_cString, "bytesplice", rb_str_bytesplice, -1);
14322 rb_define_method(rb_cString, "scrub", str_scrub, -1);
14323 rb_define_method(rb_cString, "scrub!", str_scrub_bang, -1);
14325 rb_define_method(rb_cString, "+@", str_uplus, 0);
14326 rb_define_method(rb_cString, "-@", str_uminus, 0);
14327 rb_define_method(rb_cString, "dup", rb_str_dup_m, 0);
14328 rb_define_alias(rb_cString, "dedup", "-@");
14329
14330 rb_define_method(rb_cString, "to_i", rb_str_to_i, -1);
14331 rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);
14332 rb_define_method(rb_cString, "to_s", rb_str_to_s, 0);
14333 rb_define_method(rb_cString, "to_str", rb_str_to_s, 0);
14336 rb_define_method(rb_cString, "undump", str_undump, 0);
14337
14338 sym_ascii = ID2SYM(rb_intern_const("ascii"));
14339 sym_turkic = ID2SYM(rb_intern_const("turkic"));
14340 sym_lithuanian = ID2SYM(rb_intern_const("lithuanian"));
14341 sym_fold = ID2SYM(rb_intern_const("fold"));
14342
14343 rb_define_method(rb_cString, "upcase", rb_str_upcase, -1);
14344 rb_define_method(rb_cString, "downcase", rb_str_downcase, -1);
14345 rb_define_method(rb_cString, "capitalize", rb_str_capitalize, -1);
14346 rb_define_method(rb_cString, "swapcase", rb_str_swapcase, -1);
14347
14348 rb_define_method(rb_cString, "upcase!", rb_str_upcase_bang, -1);
14349 rb_define_method(rb_cString, "downcase!", rb_str_downcase_bang, -1);
14350 rb_define_method(rb_cString, "capitalize!", rb_str_capitalize_bang, -1);
14351 rb_define_method(rb_cString, "swapcase!", rb_str_swapcase_bang, -1);
14352
14353 rb_define_method(rb_cString, "hex", rb_str_hex, 0);
14354 rb_define_method(rb_cString, "oct", rb_str_oct, 0);
14355 rb_define_method(rb_cString, "split", rb_str_split_m, -1);
14356 rb_define_method(rb_cString, "lines", rb_str_lines, -1);
14357 rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
14358 rb_define_method(rb_cString, "chars", rb_str_chars, 0);
14359 rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
14360 rb_define_method(rb_cString, "grapheme_clusters", rb_str_grapheme_clusters, 0);
14361 rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
14362 rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
14363 rb_define_method(rb_cString, "concat", rb_str_concat_multi, -1);
14364 rb_define_method(rb_cString, "append_as_bytes", rb_str_append_as_bytes, -1);
14366 rb_define_method(rb_cString, "prepend", rb_str_prepend_multi, -1);
14367 rb_define_method(rb_cString, "crypt", rb_str_crypt, 1);
14368 rb_define_method(rb_cString, "intern", rb_str_intern, 0); /* in symbol.c */
14369 rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); /* in symbol.c */
14370 rb_define_method(rb_cString, "ord", rb_str_ord, 0);
14371
14372 rb_define_method(rb_cString, "include?", rb_str_include, 1);
14373 rb_define_method(rb_cString, "start_with?", rb_str_start_with, -1);
14374 rb_define_method(rb_cString, "end_with?", rb_str_end_with, -1);
14375
14376 rb_define_method(rb_cString, "scan", rb_str_scan, 1);
14377
14378 rb_define_method(rb_cString, "ljust", rb_str_ljust, -1);
14379 rb_define_method(rb_cString, "rjust", rb_str_rjust, -1);
14380 rb_define_method(rb_cString, "center", rb_str_center, -1);
14381
14382 rb_define_method(rb_cString, "sub", rb_str_sub, -1);
14383 rb_define_method(rb_cString, "gsub", rb_str_gsub, -1);
14384 rb_define_method(rb_cString, "chop", rb_str_chop, 0);
14385 rb_define_method(rb_cString, "chomp", rb_str_chomp, -1);
14386 rb_define_method(rb_cString, "strip", rb_str_strip, -1);
14387 rb_define_method(rb_cString, "lstrip", rb_str_lstrip, -1);
14388 rb_define_method(rb_cString, "rstrip", rb_str_rstrip, -1);
14389 rb_define_method(rb_cString, "delete_prefix", rb_str_delete_prefix, 1);
14390 rb_define_method(rb_cString, "delete_suffix", rb_str_delete_suffix, 1);
14391
14392 rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1);
14393 rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1);
14394 rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0);
14395 rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1);
14396 rb_define_method(rb_cString, "strip!", rb_str_strip_bang, -1);
14397 rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, -1);
14398 rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, -1);
14399 rb_define_method(rb_cString, "delete_prefix!", rb_str_delete_prefix_bang, 1);
14400 rb_define_method(rb_cString, "delete_suffix!", rb_str_delete_suffix_bang, 1);
14401
14402 rb_define_method(rb_cString, "tr", rb_str_tr, -1);
14403 rb_define_method(rb_cString, "tr_s", rb_str_tr_s, 2);
14404 rb_define_method(rb_cString, "delete", rb_str_delete, -1);
14405 rb_define_method(rb_cString, "squeeze", rb_str_squeeze, -1);
14406 rb_define_method(rb_cString, "count", rb_str_count, -1);
14407
14408 rb_define_method(rb_cString, "tr!", rb_str_tr_bang, -1);
14409 rb_define_method(rb_cString, "tr_s!", rb_str_tr_s_bang, 2);
14410 rb_define_method(rb_cString, "delete!", rb_str_delete_bang, -1);
14411 rb_define_method(rb_cString, "squeeze!", rb_str_squeeze_bang, -1);
14412
14413 rb_define_method(rb_cString, "each_line", rb_str_each_line, -1);
14414 rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0);
14415 rb_define_method(rb_cString, "each_char", rb_str_each_char, 0);
14416 rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0);
14417 rb_define_method(rb_cString, "each_grapheme_cluster", rb_str_each_grapheme_cluster, 0);
14418
14419 rb_define_method(rb_cString, "sum", rb_str_sum, -1);
14420
14421 rb_define_method(rb_cString, "slice", rb_str_aref_m, -1);
14422 rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1);
14423
14424 rb_define_method(rb_cString, "partition", rb_str_partition, 1);
14425 rb_define_method(rb_cString, "rpartition", rb_str_rpartition, 1);
14426
14427 rb_define_method(rb_cString, "encoding", rb_obj_encoding, 0); /* in encoding.c */
14428 rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1);
14429 rb_define_method(rb_cString, "b", rb_str_b, 0);
14430
14431 /* define UnicodeNormalize module here so that we don't have to look it up */
14432 mUnicodeNormalize = rb_define_module("UnicodeNormalize");
14433 id_normalize = rb_intern_const("normalize");
14434 id_normalized_p = rb_intern_const("normalized?");
14435
14436 rb_define_method(rb_cString, "unicode_normalize", rb_str_unicode_normalize, -1);
14437 rb_define_method(rb_cString, "unicode_normalize!", rb_str_unicode_normalize_bang, -1);
14438 rb_define_method(rb_cString, "unicode_normalized?", rb_str_unicode_normalized_p, -1);
14439
14440 rb_fs = Qnil;
14441 rb_define_hooked_variable("$;", &rb_fs, 0, rb_fs_setter);
14442 rb_define_hooked_variable("$-F", &rb_fs, 0, rb_fs_setter);
14443 rb_gc_register_address(&rb_fs);
14444
14445 rb_cSymbol = rb_define_class("Symbol", rb_cObject);
14449 rb_define_singleton_method(rb_cSymbol, "all_symbols", sym_all_symbols, 0);
14450
14451 rb_define_method(rb_cSymbol, "==", sym_equal, 1);
14452 rb_define_method(rb_cSymbol, "===", sym_equal, 1);
14453 rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
14454 rb_define_method(rb_cSymbol, "to_proc", rb_sym_to_proc, 0); /* in proc.c */
14455 rb_define_method(rb_cSymbol, "succ", sym_succ, 0);
14456 rb_define_method(rb_cSymbol, "next", sym_succ, 0);
14457
14458 rb_define_method(rb_cSymbol, "<=>", sym_cmp, 1);
14459 rb_define_method(rb_cSymbol, "casecmp", sym_casecmp, 1);
14460 rb_define_method(rb_cSymbol, "casecmp?", sym_casecmp_p, 1);
14461 rb_define_method(rb_cSymbol, "=~", sym_match, 1);
14462
14463 rb_define_method(rb_cSymbol, "[]", sym_aref, -1);
14464 rb_define_method(rb_cSymbol, "slice", sym_aref, -1);
14465 rb_define_method(rb_cSymbol, "length", sym_length, 0);
14466 rb_define_method(rb_cSymbol, "size", sym_length, 0);
14467 rb_define_method(rb_cSymbol, "match", sym_match_m, -1);
14468 rb_define_method(rb_cSymbol, "match?", sym_match_m_p, -1);
14469
14470 rb_define_method(rb_cSymbol, "upcase", sym_upcase, -1);
14471 rb_define_method(rb_cSymbol, "downcase", sym_downcase, -1);
14472 rb_define_method(rb_cSymbol, "capitalize", sym_capitalize, -1);
14473 rb_define_method(rb_cSymbol, "swapcase", sym_swapcase, -1);
14474
14475 rb_define_method(rb_cSymbol, "start_with?", sym_start_with, -1);
14476 rb_define_method(rb_cSymbol, "end_with?", sym_end_with, -1);
14477
14478 rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0);
14479}
14480
14481#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:1238
static VALUE RB_OBJ_FROZEN_RAW(VALUE obj)
This is an implementation detail of RB_OBJ_FROZEN().
Definition fl_type.h:699
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
Definition fl_type.h:407
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1770
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3095
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2898
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:3385
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1035
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3174
#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:1707
#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 LEN2NUM
Old name of RB_LEN2NUM.
Definition len_t.h:29
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#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 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 NUM2LEN
Old name of RB_NUM2LEN.
Definition len_t.h:30
#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 ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#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:474
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4068
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1461
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
Definition error.c:1464
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1455
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1459
@ 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:658
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2268
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:2286
VALUE rb_obj_frozen_p(VALUE obj)
Same as RB_OBJ_FROZEN(), but returns Qtrue/Qfalse instead of #bool.
Definition object.c:1316
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:3655
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:556
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:906
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1309
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:3341
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
rb_len_t 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:2409
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1379
rb_len_t rb_memsearch(const void *x, rb_len_t m, const void *y, rb_len_t n, rb_encoding *enc)
Looks for the passed string in the passed buffer.
Definition re.c:285
VALUE rb_enc_str_new_static(const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it takes a C string literal.
Definition string.c:1244
rb_len_t 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
VALUE rb_external_str_new_with_enc(const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_external_str_new(), except it additionally takes an encoding.
Definition string.c:1385
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_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_enc_str_buf_cat(VALUE str, const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_str_cat(), except it additionally takes an encoding.
Definition string.c:3852
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(const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
Definition string.c:14205
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:14229
char * rb_enc_nth(const char *head, const char *tail, rb_len_t nth, rb_encoding *enc)
Queries the n-th character.
Definition string.c:3127
int rb_enc_symname2_p(const char *name, rb_len_t 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:1487
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:2730
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:2993
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1744
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_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
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_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:199
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
Definition vm.c:2157
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:2163
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1857
VALUE rb_range_beg_len(VALUE range, rb_len_t *begp, rb_len_t *lenp, rb_len_t len, int err)
Deconstructs a numerical range.
Definition range.c:1945
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
VALUE rb_filesystem_str_new(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it generates a string of "filesystem" encoding.
Definition string.c:1460
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2820
void rb_str_free(VALUE str)
Destroys the given string for no reason.
Definition string.c:1803
rb_len_t rb_str_offset(VALUE str, rb_len_t pos)
"Inverse" of rb_str_sublen().
Definition string.c:3155
VALUE rb_str_subseq(VALUE str, rb_len_t beg, rb_len_t len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
Definition string.c:3270
rb_len_t rb_str_strlen(VALUE str)
Counts the number of characters (not bytes) that are stored inside of the given string.
Definition string.c:2496
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:2560
#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:1608
#define rb_hash_end(h)
Just another name of st_hash_end.
Definition string.h:970
#define rb_hash_uint32(h, i)
Just another name of st_hash_uint32.
Definition string.h:964
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:3917
VALUE rb_str_tmp_new(rb_len_t len)
Allocates a "temporary" string.
Definition string.c:1797
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
Definition string.c:13837
VALUE rb_str_times(VALUE str, VALUE num)
Repetition of a string.
Definition string.c:2634
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
Definition string.c:5460
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4279
VALUE rb_utf8_str_new_static(const char *ptr, rb_len_t 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_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
void rb_str_shared_replace(VALUE dst, VALUE src)
Replaces the contents of the former with the latter.
Definition string.c:1839
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1706
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1557
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1023
rb_len_t rb_str_sublen(VALUE str, rb_len_t pos)
Byte offset to character offset conversion.
Definition string.c:3202
VALUE rb_external_str_new(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it generates a string of "default external" encoding.
Definition string.c:1436
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1555
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
Definition string.c:3504
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2038
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4265
VALUE rb_str_ellipsize(VALUE str, rb_len_t len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
Definition string.c:13152
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
Definition string.c:3685
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
Definition string.c:2056
#define rb_str_buf_new_cstr(str)
Identical to rb_str_new_cstr, except done differently.
Definition string.h:1664
VALUE rb_str_new_static(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it takes a C string literal.
Definition string.c:1209
#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:1592
VALUE rb_str_new_with_class(VALUE obj, const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it takes the class of the allocating object.
Definition string.c:1753
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:6679
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
Definition string.c:1584
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1171
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:14199
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
VALUE rb_str_drop_bytes(VALUE str, rb_len_t len)
Shrinks the given string for the given number of bytes.
Definition string.c:5862
#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:1629
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:3883
st_index_t rb_memhash(const void *ptr, rb_len_t len)
This is a universal hash function.
Definition random.c:1720
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4386
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
Definition string.c:1627
void rb_str_update(VALUE dst, rb_len_t beg, rb_len_t len, VALUE src)
Replaces some (or all) of the contents of the given string.
Definition string.c:5947
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:8156
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2866
VALUE rb_str_substr(VALUE str, rb_len_t beg, rb_len_t len)
This is the implementation of two-argumented String#slice.
Definition string.c:3367
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4333
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:4153
int rb_str_comparable(VALUE str1, VALUE str2)
Checks if two strings are comparable each other or not.
Definition string.c:4308
VALUE rb_usascii_str_new_static(const char *ptr, rb_len_t len)
Identical to rb_str_new_static(), except it generates a string of "US ASCII" encoding instead of "bin...
Definition string.c:1232
#define rb_strlen_lit(str)
Length of a string literal.
Definition string.h:1717
VALUE rb_interned_str(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it returns an infamous "f"string.
Definition string.c:14184
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:3859
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3395
char * rb_str_subpos(VALUE str, rb_len_t beg, rb_len_t *len)
Identical to rb_str_substr(), except it returns a C's string instead of Ruby's.
Definition string.c:3278
VALUE rb_str_scrub(VALUE str, VALUE repl)
"Cleanses" the string.
Definition string.c:13210
#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:1650
VALUE rb_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
Definition string.c:1769
#define rb_str_dup_frozen
Just another name of rb_str_new_frozen.
Definition string.h:656
VALUE rb_locale_str_new(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it generates a string of "locale" encoding.
Definition string.c:1448
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3051
#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:1681
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3486
#define rb_utf8_str_new(str, len)
Identical to rb_str_new, except it generates a string of "UTF-8" encoding.
Definition string.h:1574
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
Definition string.c:8273
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
Definition string.c:2510
#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:1539
VALUE rb_str_split(VALUE str, const char *delim)
Divides the given string based on the given delimiter.
Definition string.c:10808
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:1902
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:2139
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
Definition variable.c:2199
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3696
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1846
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:14151
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:14141
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
rb_len_t rb_reg_search(VALUE re, VALUE str, rb_len_t 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:974
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:57
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:3022
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:2885
#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:2898
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:1830
#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:439
#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
rb_len_t len
Length of the string, not including terminating NUL character.
Definition rstring.h:206
struct RString::@59::@60 heap
Strings that use separated memory region for contents use this pattern.
struct RBasic basic
Basic part, including flags and class.
Definition rstring.h:199
union RString::@59::@60::@62 aux
Auxiliary info.
struct RString::@59::@61 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
rb_len_t capa
Capacity of *ptr.
Definition rstring.h:232
union RString::@59 as
String's specific fields.
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
Definition string.c:9197
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Blocks until the current thread obtains a lock.
Definition thread.c:319
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:131
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
Definition value.h:148
unsigned long rb_ulen_t
An unsigned integer type that has the same width with rb_len_t.
Definition value.h:134
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