Ruby 4.1.0dev (2026-10-30 revision d531b6bc5591d858031dca55b52ea12826359a19)
string.c (d531b6bc5591d858031dca55b52ea12826359a19)
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
338/* Converts an embedded string into a heap allocated string. The buffer of an
339 * embedded string lives inside a GC heap slot, which the compactor may mprotect
340 * to implement its read barrier. A pointer to such a buffer must not be given
341 * to a system call without the GVL. */
342void
343rb_str_make_heap(VALUE str)
344{
345 if (STR_EMBED_P(str)) {
346 const int termlen = TERM_LEN(str);
347 rb_len_t len = RSTRING_LEN(str);
348 str_make_independent_expand(str, len, (rb_len_t)rb_str_capacity(str) - len, termlen);
349 }
350}
351
352void
353rb_debug_rstring_null_ptr(const char *func)
354{
355 fprintf(stderr, "%s is returning NULL!! "
356 "SIGSEGV is highly expected to follow immediately.\n"
357 "If you could reproduce, attach your debugger here, "
358 "and look at the passed string.\n",
359 func);
360}
361
362/* symbols for [up|down|swap]case/capitalize options */
363static VALUE sym_ascii, sym_turkic, sym_lithuanian, sym_fold;
364
365static rb_encoding *
366get_encoding(VALUE str)
367{
368 return rb_enc_from_index(ENCODING_GET(str));
369}
370
371static void
372mustnot_broken(VALUE str)
373{
374 if (is_broken_string(str)) {
375 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str)));
376 }
377}
378
379static void
380mustnot_wchar(VALUE str)
381{
382 rb_encoding *enc = STR_ENC_GET(str);
383 if (rb_enc_mbminlen(enc) > 1) {
384 rb_raise(rb_eArgError, "wide char encoding: %s", rb_enc_name(enc));
385 }
386}
387
388static VALUE register_fstring(VALUE str, bool copy, bool force_precompute_hash);
389
390#if SIZEOF_RB_LEN_T == SIZEOF_VOIDP
391#define PRECOMPUTED_FAKESTR_HASH 1
392#else
393#endif
394
395static inline bool
396BARE_STRING_P(VALUE str)
397{
398 return RBASIC_CLASS(str) == rb_cString && !rb_obj_shape_has_ivars(str);
399}
400
401static inline st_index_t
402str_do_hash(VALUE str)
403{
404 st_index_t h = rb_memhash((const void *)RSTRING_PTR(str), RSTRING_LEN(str));
405 int e = RSTRING_LEN(str) ? ENCODING_GET(str) : 0;
406 if (e && !is_ascii_string(str)) {
407 h = rb_hash_end(rb_hash_uint32(h, (uint32_t)e));
408 }
409 return h;
410}
411
412static VALUE
413str_store_precomputed_hash(VALUE str, st_index_t hash)
414{
415 RUBY_ASSERT(!FL_TEST_RAW(str, STR_PRECOMPUTED_HASH));
416 RUBY_ASSERT(STR_EMBED_P(str));
417
418#if RUBY_DEBUG
419 size_t used_bytes = (RSTRING_LEN(str) + TERM_LEN(str));
420 size_t free_bytes = str_embed_capa(str) - used_bytes;
421 RUBY_ASSERT(free_bytes >= sizeof(st_index_t));
422#endif
423
424 memcpy(RSTRING_END(str) + TERM_LEN(str), &hash, sizeof(hash));
425
426 FL_SET(str, STR_PRECOMPUTED_HASH);
427
428 return str;
429}
430
431VALUE
432rb_fstring(VALUE str)
433{
434 VALUE fstr;
435 int bare;
436
437 Check_Type(str, T_STRING);
438
439 if (FL_TEST(str, RSTRING_FSTR))
440 return str;
441
442 bare = BARE_STRING_P(str);
443 if (!bare) {
444 if (STR_EMBED_P(str)) {
445 OBJ_FREEZE(str);
446 return str;
447 }
448
449 if (FL_TEST_RAW(str, STR_SHARED_ROOT | STR_SHARED) == STR_SHARED_ROOT) {
451 return str;
452 }
453 }
454
455 if (!FL_TEST_RAW(str, FL_FREEZE | STR_NOFREE | STR_CHILLED))
456 rb_str_resize(str, RSTRING_LEN(str));
457
458 fstr = register_fstring(str, false, false);
459
460 if (!bare) {
461 str_replace_shared_without_enc(str, fstr);
462 OBJ_FREEZE(str);
463 return str;
464 }
465 return fstr;
466}
467
468static VALUE fstring_table_obj;
469
470static VALUE
471fstring_concurrent_set_hash(VALUE str)
472{
473#ifdef PRECOMPUTED_FAKESTR_HASH
474 st_index_t h;
475 if (FL_TEST_RAW(str, STR_FAKESTR)) {
476 // register_fstring precomputes the hash and stores it in capa for fake strings
477 h = (st_index_t)RSTRING(str)->as.heap.aux.capa;
478 }
479 else {
480 h = rb_str_hash(str);
481 }
482 // rb_str_hash doesn't include the encoding for ascii only strings, so
483 // we add it to avoid common collisions between `:sym.name` (ASCII) and `"sym"` (UTF-8)
484 return (VALUE)rb_hash_end(rb_hash_uint32(h, (uint32_t)ENCODING_GET_INLINED(str)));
485#else
486 return (VALUE)rb_str_hash(str);
487#endif
488}
489
490static bool
491fstring_concurrent_set_cmp(VALUE a, VALUE b)
492{
493 rb_len_t alen, blen;
494 const char *aptr, *bptr;
495
498
499 RSTRING_GETMEM(a, aptr, alen);
500 RSTRING_GETMEM(b, bptr, blen);
501 return (alen == blen &&
502 ENCODING_GET(a) == ENCODING_GET(b) &&
503 memcmp(aptr, bptr, alen) == 0);
504}
505
507 bool copy;
508 bool force_precompute_hash;
509};
510
511static VALUE
512fstring_concurrent_set_create(VALUE str, void *data)
513{
514 struct fstr_create_arg *arg = data;
515
516 // Unless the string is empty or binary, its coderange has been precomputed.
517 int coderange = ENC_CODERANGE(str);
518
519 if (FL_TEST_RAW(str, STR_FAKESTR)) {
520 if (arg->copy) {
521 VALUE new_str;
522 rb_len_t len = RSTRING_LEN(str);
523 rb_len_t capa = len + sizeof(st_index_t);
524 int term_len = TERM_LEN(str);
525
526 if (arg->force_precompute_hash && STR_EMBEDDABLE_P(capa, term_len)) {
527 new_str = str_alloc_embed(rb_cString, capa + term_len);
528 memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str), len);
529 STR_SET_LEN(new_str, RSTRING_LEN(str));
530 TERM_FILL(RSTRING_END(new_str), TERM_LEN(str));
531 rb_enc_copy(new_str, str);
532 str_store_precomputed_hash(new_str, str_do_hash(str));
533 }
534 else {
535 new_str = str_new(rb_cString, RSTRING(str)->as.heap.ptr, RSTRING(str)->len);
536 rb_enc_copy(new_str, str);
537#ifdef PRECOMPUTED_FAKESTR_HASH
538 if (rb_str_capacity(new_str) >= RSTRING_LEN(str) + term_len + sizeof(st_index_t)) {
539 str_store_precomputed_hash(new_str, (st_index_t)RSTRING(str)->as.heap.aux.capa);
540 }
541#endif
542 }
543 str = new_str;
544 }
545 else {
546 str = str_new_static(rb_cString, RSTRING(str)->as.heap.ptr,
547 RSTRING(str)->len,
548 ENCODING_GET(str));
549 }
550 OBJ_FREEZE(str);
551 }
552 else {
553 if (!OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
554 str = str_new_frozen(rb_cString, str);
555 }
556 if (STR_SHARED_P(str)) { /* str should not be shared */
557 /* shared substring */
558 str_make_independent(str);
560 }
561 if (!BARE_STRING_P(str)) {
562 str = str_new_frozen(rb_cString, str);
563 }
564 }
565
566 ENC_CODERANGE_SET(str, coderange);
567 RBASIC(str)->flags |= RSTRING_FSTR;
568 if (!RB_OBJ_SHAREABLE_P(str)) {
570 }
571 RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
574 RUBY_ASSERT(!FL_TEST_RAW(str, STR_FAKESTR));
575 RUBY_ASSERT(!rb_obj_shape_has_ivars(str));
577 RUBY_ASSERT(!rb_objspace_garbage_object_p(str));
578
579 return str;
580}
581
582static const struct rb_concurrent_set_funcs fstring_concurrent_set_funcs = {
583 .hash = fstring_concurrent_set_hash,
584 .cmp = fstring_concurrent_set_cmp,
585 .create = fstring_concurrent_set_create,
586 .free = NULL,
587};
588
589void
590Init_fstring_table(void)
591{
592 fstring_table_obj = rb_concurrent_set_new(&fstring_concurrent_set_funcs, 8192);
593 rb_gc_register_address(&fstring_table_obj);
594}
595
596static VALUE
597register_fstring(VALUE str, bool copy, bool force_precompute_hash)
598{
599 struct fstr_create_arg args = {
600 .copy = copy,
601 .force_precompute_hash = force_precompute_hash
602 };
603
604#ifdef PRECOMPUTED_FAKESTR_HASH
605 if (FL_TEST_RAW(str, STR_FAKESTR)) {
606 // if the string hasn't been interned, we'll need the hash twice, so we
607 // compute it once and store it in capa
608 RSTRING(str)->as.heap.aux.capa = (rb_len_t)str_do_hash(str);
609 }
610#endif
611
612 VALUE result = rb_concurrent_set_find_or_insert(&fstring_table_obj, str, &args);
613
614 RUBY_ASSERT(!rb_objspace_garbage_object_p(result));
616 RUBY_ASSERT(OBJ_FROZEN(result));
618 RUBY_ASSERT((rb_gc_verify_shareable(result), 1));
619 RUBY_ASSERT(!FL_TEST_RAW(result, STR_FAKESTR));
621
622 return result;
623}
624
625bool
626rb_obj_is_fstring_table(VALUE obj)
627{
628 ASSERT_vm_locking();
629
630 return obj == fstring_table_obj;
631}
632
633void
634rb_gc_free_fstring(VALUE obj)
635{
636 ASSERT_vm_locking_with_barrier();
637
638 RUBY_ASSERT(FL_TEST(obj, RSTRING_FSTR));
640 RUBY_ASSERT(!FL_TEST(obj, STR_SHARED));
641
642 rb_concurrent_set_delete_by_identity(fstring_table_obj, obj);
643
644 RB_DEBUG_COUNTER_INC(obj_str_fstr);
645
646 FL_UNSET(obj, RSTRING_FSTR);
647}
648
649void
650rb_fstring_foreach_with_replace(int (*callback)(VALUE *str, void *data), void *data)
651{
652 if (fstring_table_obj) {
653 rb_concurrent_set_foreach_with_replace(fstring_table_obj, callback, data);
654 }
655}
656
657static VALUE
658setup_fake_str(struct RString *fake_str, const char *name, rb_len_t len, int encidx)
659{
660 fake_str->basic.flags = T_STRING|RSTRING_NOEMBED|STR_NOFREE|STR_FAKESTR;
661 RBASIC_SET_FULL_SHAPE_ID((VALUE)fake_str, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
662
663 if (!name) {
665 name = "";
666 }
667
668 ENCODING_SET_INLINED((VALUE)fake_str, encidx);
669
670 RBASIC_SET_CLASS_RAW((VALUE)fake_str, rb_cString);
671 fake_str->len = len;
672 fake_str->as.heap.ptr = (char *)name;
673 fake_str->as.heap.aux.capa = len;
674 return (VALUE)fake_str;
675}
676
677/*
678 * set up a fake string which refers a static string literal.
679 */
680VALUE
681rb_setup_fake_str(struct RString *fake_str, const char *name, rb_len_t len, rb_encoding *enc)
682{
683 return setup_fake_str(fake_str, name, len, rb_enc_to_index(enc));
684}
685
686/*
687 * rb_fstring_new and rb_fstring_cstr family create or lookup a frozen
688 * shared string which refers a static string literal. `ptr` must
689 * point a constant string.
690 */
691VALUE
692rb_fstring_new(const char *ptr, rb_len_t len)
693{
694 struct RString fake_str = {RBASIC_INIT};
695 return register_fstring(setup_fake_str(&fake_str, ptr, len, ENCINDEX_US_ASCII), false, false);
696}
697
698VALUE
699rb_fstring_enc_new(const char *ptr, rb_len_t len, rb_encoding *enc)
700{
701 struct RString fake_str = {RBASIC_INIT};
702 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), false, false);
703}
704
705VALUE
706rb_fstring_cstr(const char *ptr)
707{
708 return rb_fstring_new(ptr, strlen(ptr));
709}
710
711static inline bool
712single_byte_optimizable(VALUE str)
713{
714 int encindex = ENCODING_GET(str);
715 switch (encindex) {
716 case ENCINDEX_ASCII_8BIT:
717 case ENCINDEX_US_ASCII:
718 return true;
719 case ENCINDEX_UTF_8:
720 // For UTF-8 it's worth scanning the string coderange when unknown.
721 return rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT;
722 }
723 /* Conservative. It may be ENC_CODERANGE_UNKNOWN. */
724 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
725 return true;
726 }
727
728 if (rb_enc_mbmaxlen(rb_enc_from_index(encindex)) == 1) {
729 return true;
730 }
731
732 /* Conservative. Possibly single byte.
733 * "\xa1" in Shift_JIS for example. */
734 return false;
735}
736
738
739static inline const char *
740search_nonascii(const char *p, const char *e)
741{
742 const char *s, *t;
743
744 if (p < e && !ISASCII(*p)) {
745 return p;
746 }
747
748#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
749# if SIZEOF_UINTPTR_T == 8
750# define NONASCII_MASK UINT64_C(0x8080808080808080)
751# elif SIZEOF_UINTPTR_T == 4
752# define NONASCII_MASK UINT32_C(0x80808080)
753# else
754# error "don't know what to do."
755# endif
756#else
757# if SIZEOF_UINTPTR_T == 8
758# define NONASCII_MASK ((uintptr_t)0x80808080UL << 32 | (uintptr_t)0x80808080UL)
759# elif SIZEOF_UINTPTR_T == 4
760# define NONASCII_MASK 0x80808080UL /* or...? */
761# else
762# error "don't know what to do."
763# endif
764#endif
765
766 if (UNALIGNED_WORD_ACCESS || e - p >= SIZEOF_VOIDP) {
767#if !UNALIGNED_WORD_ACCESS
768 if ((uintptr_t)p % SIZEOF_VOIDP) {
769 int l = SIZEOF_VOIDP - (uintptr_t)p % SIZEOF_VOIDP;
770 p += l;
771 switch (l) {
772 default: UNREACHABLE;
773#if SIZEOF_VOIDP > 4
774 case 7: if (p[-7]&0x80) return p-7;
775 case 6: if (p[-6]&0x80) return p-6;
776 case 5: if (p[-5]&0x80) return p-5;
777 case 4: if (p[-4]&0x80) return p-4;
778#endif
779 case 3: if (p[-3]&0x80) return p-3;
780 case 2: if (p[-2]&0x80) return p-2;
781 case 1: if (p[-1]&0x80) return p-1;
782 case 0: break;
783 }
784 }
785#endif
786#if defined(HAVE_BUILTIN___BUILTIN_ASSUME_ALIGNED) &&! UNALIGNED_WORD_ACCESS
787#define aligned_ptr(value) \
788 __builtin_assume_aligned((value), sizeof(uintptr_t))
789#else
790#define aligned_ptr(value) (value)
791#endif
792 s = aligned_ptr(p);
793 t = (e - (SIZEOF_VOIDP-1));
794#undef aligned_ptr
795 for (;s < t; s += sizeof(uintptr_t)) {
796 uintptr_t word;
797 memcpy(&word, s, sizeof(word));
798 if (word & NONASCII_MASK) {
799#ifdef WORDS_BIGENDIAN
800 return (const char *)s + (nlz_intptr(word&NONASCII_MASK)>>3);
801#else
802 return (const char *)s + (ntz_intptr(word&NONASCII_MASK)>>3);
803#endif
804 }
805 }
806 p = (const char *)s;
807 }
808
809 switch (e - p) {
810 default: UNREACHABLE;
811#if SIZEOF_VOIDP > 4
812 case 7: if (e[-7]&0x80) return e-7;
813 case 6: if (e[-6]&0x80) return e-6;
814 case 5: if (e[-5]&0x80) return e-5;
815 case 4: if (e[-4]&0x80) return e-4;
816#endif
817 case 3: if (e[-3]&0x80) return e-3;
818 case 2: if (e[-2]&0x80) return e-2;
819 case 1: if (e[-1]&0x80) return e-1;
820 case 0: return NULL;
821 }
822}
823
824static int
825coderange_scan(const char *p, rb_len_t len, rb_encoding *enc)
826{
827 const char *e = p + len;
828
829 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
830 /* enc is ASCII-8BIT. ASCII-8BIT string never be broken. */
831 p = search_nonascii(p, e);
833 }
834
835 if (rb_enc_asciicompat(enc)) {
836 p = search_nonascii(p, e);
837 if (!p) return ENC_CODERANGE_7BIT;
838 for (;;) {
839 int ret = rb_enc_precise_mbclen(p, e, enc);
841 p += MBCLEN_CHARFOUND_LEN(ret);
842 if (p == e) break;
843 p = search_nonascii(p, e);
844 if (!p) break;
845 }
846 }
847 else {
848 while (p < e) {
849 int ret = rb_enc_precise_mbclen(p, e, enc);
851 p += MBCLEN_CHARFOUND_LEN(ret);
852 }
853 }
854 return ENC_CODERANGE_VALID;
855}
856
858rb_str_coderange_scan_restartable(const char *s, const char *e, rb_encoding *enc, int *cr)
859{
860 const char *p = s;
861
862 if (*cr == ENC_CODERANGE_BROKEN)
863 return e - s;
864
865 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
866 /* enc is ASCII-8BIT. ASCII-8BIT string never be broken. */
867 if (*cr == ENC_CODERANGE_VALID) return e - s;
868 p = search_nonascii(p, e);
870 return e - s;
871 }
872 else if (rb_enc_asciicompat(enc)) {
873 p = search_nonascii(p, e);
874 if (!p) {
875 if (*cr != ENC_CODERANGE_VALID) *cr = ENC_CODERANGE_7BIT;
876 return e - s;
877 }
878 for (;;) {
879 int ret = rb_enc_precise_mbclen(p, e, enc);
880 if (!MBCLEN_CHARFOUND_P(ret)) {
882 return p - s;
883 }
884 p += MBCLEN_CHARFOUND_LEN(ret);
885 if (p == e) break;
886 p = search_nonascii(p, e);
887 if (!p) break;
888 }
889 }
890 else {
891 while (p < e) {
892 int ret = rb_enc_precise_mbclen(p, e, enc);
893 if (!MBCLEN_CHARFOUND_P(ret)) {
895 return p - s;
896 }
897 p += MBCLEN_CHARFOUND_LEN(ret);
898 }
899 }
901 return e - s;
902}
903
904static inline void
905str_enc_copy(VALUE str1, VALUE str2)
906{
907 rb_enc_set_index(str1, ENCODING_GET(str2));
908}
909
910/* Like str_enc_copy, but does not check frozen status of str1.
911 * You should use this only if you're certain that str1 is not frozen. */
912static inline void
913str_enc_copy_direct(VALUE str1, VALUE str2)
914{
915 int inlined_encoding = RB_ENCODING_GET_INLINED(str2);
916 if (inlined_encoding == ENCODING_INLINE_MAX) {
917 rb_enc_set_index(str1, rb_enc_get_index(str2));
918 }
919 else {
920 ENCODING_SET_INLINED(str1, inlined_encoding);
921 }
922}
923
924static void
925rb_enc_cr_str_copy_for_substr(VALUE dest, VALUE src)
926{
927 /* this function is designed for copying encoding and coderange
928 * from src to new string "dest" which is made from the part of src.
929 */
930 str_enc_copy(dest, src);
931 if (RSTRING_LEN(dest) == 0) {
932 if (!rb_enc_asciicompat(STR_ENC_GET(src)))
934 else
936 return;
937 }
938 switch (ENC_CODERANGE(src)) {
941 break;
943 if (!rb_enc_asciicompat(STR_ENC_GET(src)) ||
944 search_nonascii(RSTRING_PTR(dest), RSTRING_END(dest)))
946 else
948 break;
949 default:
950 break;
951 }
952}
953
954static void
955rb_enc_cr_str_exact_copy(VALUE dest, VALUE src)
956{
957 str_enc_copy(dest, src);
959}
960
961static int
962enc_coderange_scan(VALUE str, rb_encoding *enc)
963{
964 return coderange_scan(RSTRING_PTR(str), RSTRING_LEN(str), enc);
965}
966
967int
968rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc)
969{
970 return enc_coderange_scan(str, enc);
971}
972
973int
974rbimpl_enc_str_coderange_scan(VALUE str)
975{
976 int cr = enc_coderange_scan(str, get_encoding(str));
977 ENC_CODERANGE_SET(str, cr);
978 return cr;
979}
980
981#undef rb_enc_str_coderange
982int
983rb_enc_str_coderange(VALUE str)
984{
985 int cr = ENC_CODERANGE(str);
986
987 if (cr == ENC_CODERANGE_UNKNOWN) {
988 cr = rbimpl_enc_str_coderange_scan(str);
989 }
990 return cr;
991}
992#define rb_enc_str_coderange rb_enc_str_coderange_inline
993
994static inline bool
995rb_enc_str_asciicompat(VALUE str)
996{
997 int encindex = ENCODING_GET_INLINED(str);
998 return rb_str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
999}
1000
1001int
1003{
1004 switch(ENC_CODERANGE(str)) {
1006 return rb_enc_str_asciicompat(str) && is_ascii_string(str);
1007 case ENC_CODERANGE_7BIT:
1008 return true;
1009 default:
1010 return false;
1011 }
1012}
1013
1014static inline void
1015str_mod_check(VALUE s, const char *p, rb_len_t len)
1016{
1017 if (RSTRING_PTR(s) != p || RSTRING_LEN(s) != len){
1018 rb_raise(rb_eRuntimeError, "string modified");
1019 }
1020}
1021
1022static size_t
1023str_capacity(VALUE str, const int termlen)
1024{
1025 if (STR_EMBED_P(str)) {
1026 return str_embed_capa(str) - termlen;
1027 }
1028 else if (FL_ANY_RAW(str, STR_SHARED|STR_NOFREE)) {
1029 return RSTRING(str)->len;
1030 }
1031 else {
1032 return RSTRING(str)->as.heap.aux.capa;
1033 }
1034}
1035
1036size_t
1038{
1039 return str_capacity(str, TERM_LEN(str));
1040}
1041
1042static inline void
1043must_not_null(const char *ptr)
1044{
1045 if (!ptr) {
1046 rb_raise(rb_eArgError, "NULL pointer given");
1047 }
1048}
1049
1050static inline VALUE
1051str_alloc_embed(VALUE klass, size_t capa)
1052{
1053 size_t size = rb_str_embed_size(capa, 0);
1054 RUBY_ASSERT(size > 0);
1055 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
1056
1057 NEWOBJ_OF(str, struct RString, klass, T_STRING, size);
1058
1059 str->len = 0;
1060 str->as.embed.ary[0] = 0;
1061
1062 return (VALUE)str;
1063}
1064
1065static inline VALUE
1066str_alloc_heap(VALUE klass)
1067{
1068 NEWOBJ_OF(str, struct RString, klass, T_STRING | STR_NOEMBED, sizeof(struct RString));
1069
1070 str->len = 0;
1071 str->as.heap.aux.capa = 0;
1072 str->as.heap.ptr = NULL;
1073
1074 return (VALUE)str;
1075}
1076
1077static inline VALUE
1078empty_str_alloc(VALUE klass)
1079{
1080 RUBY_DTRACE_CREATE_HOOK(STRING, 0);
1081 VALUE str = str_alloc_embed(klass, 0);
1082 memset(RSTRING(str)->as.embed.ary, 0, str_embed_capa(str));
1084 return str;
1085}
1086
1087static VALUE
1088str_enc_new(VALUE klass, const char *ptr, rb_len_t len, rb_encoding *enc)
1089{
1090 VALUE str;
1091
1092 if (len < 0) {
1093 rb_raise(rb_eArgError, "negative string size (or size too big)");
1094 }
1095
1096 if (enc == NULL) {
1097 enc = rb_ascii8bit_encoding();
1098 }
1099
1100 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1101
1102 int termlen = rb_enc_mbminlen(enc);
1103
1104 if (STR_EMBEDDABLE_P(len, termlen)) {
1105 str = str_alloc_embed(klass, len + termlen);
1106 if (len == 0) {
1107 ENC_CODERANGE_SET(str, rb_enc_asciicompat(enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
1108 }
1109 }
1110 else {
1111 str = str_alloc_heap(klass);
1112 RSTRING(str)->as.heap.aux.capa = len;
1113 /* :FIXME: @shyouhei guesses `len + termlen` is guaranteed to never
1114 * integer overflow. If we can STATIC_ASSERT that, the following
1115 * mul_add_mul can be reverted to a simple ALLOC_N. */
1116 RSTRING(str)->as.heap.ptr =
1117 rb_xmalloc_mul_add_mul(sizeof(char), len, sizeof(char), termlen);
1118 }
1119
1120 rb_enc_raw_set(str, enc);
1121
1122 if (ptr) {
1123 memcpy(RSTRING_PTR(str), ptr, len);
1124 }
1125 else {
1126 memset(RSTRING_PTR(str), 0, len);
1127 }
1128
1129 STR_SET_LEN(str, len);
1130 TERM_FILL(RSTRING_PTR(str) + len, termlen);
1131 return str;
1132}
1133
1134static VALUE
1135str_new(VALUE klass, const char *ptr, rb_len_t len)
1136{
1137 return str_enc_new(klass, ptr, len, rb_ascii8bit_encoding());
1138}
1139
1140VALUE
1142{
1143 return str_new(rb_cString, ptr, len);
1144}
1145
1146VALUE
1148{
1149 return str_enc_new(rb_cString, ptr, len, rb_usascii_encoding());
1150}
1151
1152VALUE
1154{
1155 return str_enc_new(rb_cString, ptr, len, rb_utf8_encoding());
1156}
1157
1158VALUE
1159rb_enc_str_new(const char *ptr, rb_len_t len, rb_encoding *enc)
1160{
1161 return str_enc_new(rb_cString, ptr, len, enc);
1162}
1163
1164VALUE
1166{
1167 must_not_null(ptr);
1168 /* rb_str_new_cstr() can take pointer from non-malloc-generated
1169 * memory regions, and that cannot be detected by the MSAN. Just
1170 * trust the programmer that the argument passed here is a sane C
1171 * string. */
1172 __msan_unpoison_string(ptr);
1173 return rb_str_new(ptr, strlen(ptr));
1174}
1175
1176VALUE
1178{
1179 return rb_enc_str_new_cstr(ptr, rb_usascii_encoding());
1180}
1181
1182VALUE
1184{
1185 return rb_enc_str_new_cstr(ptr, rb_utf8_encoding());
1186}
1187
1188VALUE
1190{
1191 must_not_null(ptr);
1192 if (rb_enc_mbminlen(enc) != 1) {
1193 rb_raise(rb_eArgError, "wchar encoding given");
1194 }
1195 return rb_enc_str_new(ptr, strlen(ptr), enc);
1196}
1197
1198static VALUE
1199str_new_static(VALUE klass, const char *ptr, rb_len_t len, int encindex)
1200{
1201 VALUE str;
1202
1203 if (len < 0) {
1204 rb_raise(rb_eArgError, "negative string size (or size too big)");
1205 }
1206
1207 if (!ptr) {
1208 str = str_enc_new(klass, ptr, len, rb_enc_from_index(encindex));
1209 }
1210 else {
1211 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1212 str = str_alloc_heap(klass);
1213 RSTRING(str)->len = len;
1214 RSTRING(str)->as.heap.ptr = (char *)ptr;
1215 RSTRING(str)->as.heap.aux.capa = len;
1216 RBASIC(str)->flags |= STR_NOFREE;
1217 rb_enc_associate_index(str, encindex);
1218 }
1219 return str;
1220}
1221
1222VALUE
1224{
1225 return str_new_static(rb_cString, ptr, len, 0);
1226}
1227
1228/* Take an xmalloc'd buffer as the String's body without copying it; the String owns it
1229 * from here and frees it like any other heap string. ptr must hold capa bytes plus the
1230 * terminator for encindex, which is what a Ractor courier's string node carries. */
1231VALUE
1232rb_str_new_owned(char *ptr, rb_len_t len, rb_len_t capa, int encindex)
1233{
1234 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1235 VALUE str = str_alloc_heap(rb_cString);
1236 RSTRING(str)->len = len;
1237 RSTRING(str)->as.heap.ptr = ptr;
1238 /* Freed by size (STR_HEAP_SIZE = capa + terminator), so capa must describe the
1239 * allocation the caller made, not just the bytes in use. */
1240 RSTRING(str)->as.heap.aux.capa = capa;
1241 rb_enc_associate_index(str, encindex);
1242 return str;
1243}
1244
1245VALUE
1247{
1248 return str_new_static(rb_cString, ptr, len, ENCINDEX_US_ASCII);
1249}
1250
1251VALUE
1253{
1254 return str_new_static(rb_cString, ptr, len, ENCINDEX_UTF_8);
1255}
1256
1257VALUE
1259{
1260 return str_new_static(rb_cString, ptr, len, rb_enc_to_index(enc));
1261}
1262
1263static VALUE str_cat_conv_enc_opts(VALUE newstr, rb_len_t ofs, const char *ptr, rb_len_t len,
1264 rb_encoding *from, rb_encoding *to,
1265 int ecflags, VALUE ecopts);
1266
1267static inline bool
1268is_enc_ascii_string(VALUE str, rb_encoding *enc)
1269{
1270 int encidx = rb_enc_to_index(enc);
1271 if (rb_enc_get_index(str) == encidx)
1272 return is_ascii_string(str);
1273 return enc_coderange_scan(str, enc) == ENC_CODERANGE_7BIT;
1274}
1275
1276VALUE
1277rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
1278{
1279 rb_len_t len;
1280 const char *ptr;
1281 VALUE newstr;
1282
1283 if (!to) return str;
1284 if (!from) from = rb_enc_get(str);
1285 if (from == to) return str;
1286 if ((rb_enc_asciicompat(to) && is_enc_ascii_string(str, from)) ||
1287 rb_is_ascii8bit_enc(to)) {
1288 if (STR_ENC_GET(str) != to) {
1289 str = rb_str_dup(str);
1290 rb_enc_associate(str, to);
1291 }
1292 return str;
1293 }
1294
1295 RSTRING_GETMEM(str, ptr, len);
1296 newstr = str_cat_conv_enc_opts(rb_str_buf_new(len), 0, ptr, len,
1297 from, to, ecflags, ecopts);
1298 if (NIL_P(newstr)) {
1299 /* some error, return original */
1300 return str;
1301 }
1302 return newstr;
1303}
1304
1305VALUE
1306rb_str_cat_conv_enc_opts(VALUE newstr, rb_len_t ofs, const char *ptr, rb_len_t len,
1307 rb_encoding *from, int ecflags, VALUE ecopts)
1308{
1309 rb_len_t olen;
1310
1311 olen = RSTRING_LEN(newstr);
1312 if (ofs < -olen || olen < ofs)
1313 rb_raise(rb_eIndexError, "index %"PRIdLEN" out of string", ofs);
1314 if (ofs < 0) ofs += olen;
1315 if (!from) {
1316 STR_SET_LEN(newstr, ofs);
1317 return rb_str_cat(newstr, ptr, len);
1318 }
1319
1320 rb_str_modify(newstr);
1321 return str_cat_conv_enc_opts(newstr, ofs, ptr, len, from,
1322 rb_enc_get(newstr),
1323 ecflags, ecopts);
1324}
1325
1326VALUE
1327rb_str_initialize(VALUE str, const char *ptr, rb_len_t len, rb_encoding *enc)
1328{
1329 STR_SET_LEN(str, 0);
1330 rb_enc_associate(str, enc);
1331 rb_str_cat(str, ptr, len);
1332 return str;
1333}
1334
1335static VALUE
1336str_cat_conv_enc_opts(VALUE newstr, rb_len_t ofs, const char *ptr, rb_len_t len,
1337 rb_encoding *from, rb_encoding *to,
1338 int ecflags, VALUE ecopts)
1339{
1340 rb_econv_t *ec;
1342 rb_len_t olen;
1343 VALUE econv_wrapper;
1344 const unsigned char *start, *sp;
1345 unsigned char *dest, *dp;
1346 size_t converted_output = (size_t)ofs;
1347
1348 olen = rb_str_capacity(newstr);
1349
1350 econv_wrapper = rb_obj_alloc(rb_cEncodingConverter);
1351 RBASIC_CLEAR_CLASS(econv_wrapper);
1352 ec = rb_econv_open_opts(from->name, to->name, ecflags, ecopts);
1353 if (!ec) return Qnil;
1354 DATA_PTR(econv_wrapper) = ec;
1355
1356 sp = (unsigned char*)ptr;
1357 start = sp;
1358 while ((dest = (unsigned char*)RSTRING_PTR(newstr)),
1359 (dp = dest + converted_output),
1360 (ret = rb_econv_convert(ec, &sp, start + len, &dp, dest + olen, 0)),
1362 /* destination buffer short */
1363 size_t converted_input = sp - start;
1364 size_t rest = len - converted_input;
1365 converted_output = dp - dest;
1366 rb_str_set_len(newstr, converted_output);
1367 if (converted_input && converted_output &&
1368 rest < (RB_LEN_MAX / converted_output)) {
1369 rest = (rest * converted_output) / converted_input;
1370 }
1371 else {
1372 rest = olen;
1373 }
1374 olen += rest < 2 ? 2 : rest;
1375 rb_str_resize(newstr, olen);
1376 }
1377 DATA_PTR(econv_wrapper) = 0;
1378 RB_GC_GUARD(econv_wrapper);
1379 rb_econv_close(ec);
1380 switch (ret) {
1381 case econv_finished:
1382 len = dp - (unsigned char*)RSTRING_PTR(newstr);
1383 rb_str_set_len(newstr, len);
1384 rb_enc_associate(newstr, to);
1385 return newstr;
1386
1387 default:
1388 return Qnil;
1389 }
1390}
1391
1392VALUE
1394{
1395 return rb_str_conv_enc_opts(str, from, to, 0, Qnil);
1396}
1397
1398VALUE
1400{
1401 rb_encoding *ienc;
1402 VALUE str;
1403 const int eidx = rb_enc_to_index(eenc);
1404
1405 if (!ptr) {
1406 return rb_enc_str_new(ptr, len, eenc);
1407 }
1408
1409 /* ASCII-8BIT case, no conversion */
1410 if ((eidx == rb_ascii8bit_encindex()) ||
1411 (eidx == rb_usascii_encindex() && search_nonascii(ptr, ptr + len))) {
1412 return rb_str_new(ptr, len);
1413 }
1414 /* no default_internal or same encoding, no conversion */
1415 ienc = rb_default_internal_encoding();
1416 if (!ienc || eenc == ienc) {
1417 return rb_enc_str_new(ptr, len, eenc);
1418 }
1419 /* ASCII compatible, and ASCII only string, no conversion in
1420 * default_internal */
1421 if ((eidx == rb_ascii8bit_encindex()) ||
1422 (eidx == rb_usascii_encindex()) ||
1423 (rb_enc_asciicompat(eenc) && !search_nonascii(ptr, ptr + len))) {
1424 return rb_enc_str_new(ptr, len, ienc);
1425 }
1426 /* convert from the given encoding to default_internal */
1427 str = rb_enc_str_new(NULL, 0, ienc);
1428 /* when the conversion failed for some reason, just ignore the
1429 * default_internal and result in the given encoding as-is. */
1430 if (NIL_P(rb_str_cat_conv_enc_opts(str, 0, ptr, len, eenc, 0, Qnil))) {
1431 rb_str_initialize(str, ptr, len, eenc);
1432 }
1433 return str;
1434}
1435
1436VALUE
1437rb_external_str_with_enc(VALUE str, rb_encoding *eenc)
1438{
1439 int eidx = rb_enc_to_index(eenc);
1440 if (eidx == rb_usascii_encindex() &&
1441 !is_ascii_string(str)) {
1442 rb_enc_associate_index(str, rb_ascii8bit_encindex());
1443 return str;
1444 }
1445 rb_enc_associate_index(str, eidx);
1446 return rb_str_conv_enc(str, eenc, rb_default_internal_encoding());
1447}
1448
1449VALUE
1451{
1452 return rb_external_str_new_with_enc(ptr, len, rb_default_external_encoding());
1453}
1454
1455VALUE
1457{
1458 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_default_external_encoding());
1459}
1460
1461VALUE
1463{
1464 return rb_external_str_new_with_enc(ptr, len, rb_locale_encoding());
1465}
1466
1467VALUE
1469{
1470 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_locale_encoding());
1471}
1472
1473VALUE
1475{
1476 return rb_external_str_new_with_enc(ptr, len, rb_filesystem_encoding());
1477}
1478
1479VALUE
1481{
1482 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_filesystem_encoding());
1483}
1484
1485VALUE
1487{
1488 return rb_str_export_to_enc(str, rb_default_external_encoding());
1489}
1490
1491VALUE
1493{
1494 return rb_str_export_to_enc(str, rb_locale_encoding());
1495}
1496
1497VALUE
1499{
1500 return rb_str_conv_enc(str, STR_ENC_GET(str), enc);
1501}
1502
1503static VALUE
1504str_replace_shared_without_enc(VALUE str2, VALUE str)
1505{
1506 const int termlen = TERM_LEN(str);
1507 char *ptr;
1508 rb_len_t len;
1509
1510 RSTRING_GETMEM(str, ptr, len);
1511 if (str_embed_capa(str2) >= len + termlen) {
1512 char *ptr2 = RSTRING(str2)->as.embed.ary;
1513 STR_SET_EMBED(str2);
1514 memcpy(ptr2, RSTRING_PTR(str), len);
1515 TERM_FILL(ptr2+len, termlen);
1516 }
1517 else {
1518 VALUE root;
1519 if (STR_SHARED_P(str)) {
1520 root = RSTRING(str)->as.heap.aux.shared;
1521 RSTRING_GETMEM(str, ptr, len);
1522 }
1523 else {
1524 root = rb_str_new_frozen(str);
1525 RSTRING_GETMEM(root, ptr, len);
1526 }
1527 RUBY_ASSERT(OBJ_FROZEN(root));
1528
1529 if (!STR_EMBED_P(str2) && !FL_TEST_RAW(str2, STR_SHARED|STR_NOFREE)) {
1530 if (FL_TEST_RAW(str2, STR_SHARED_ROOT)) {
1531 rb_fatal("about to free a possible shared root");
1532 }
1533 char *ptr2 = STR_HEAP_PTR(str2);
1534 if (ptr2 != ptr) {
1535 SIZED_FREE_N(ptr2, STR_HEAP_SIZE(str2));
1536 }
1537 }
1538 FL_SET(str2, STR_NOEMBED);
1539 RSTRING(str2)->as.heap.ptr = ptr;
1540 STR_SET_SHARED(str2, root);
1541 }
1542
1543 STR_SET_LEN(str2, len);
1544
1545 return str2;
1546}
1547
1548static VALUE
1549str_replace_shared(VALUE str2, VALUE str)
1550{
1551 str_replace_shared_without_enc(str2, str);
1552 rb_enc_cr_str_exact_copy(str2, str);
1553 return str2;
1554}
1555
1556static VALUE
1557str_new_shared(VALUE klass, VALUE str)
1558{
1559 return str_replace_shared(str_alloc_heap(klass), str);
1560}
1561
1562VALUE
1564{
1565 return str_new_shared(rb_obj_class(str), str);
1566}
1567
1568VALUE
1570{
1571 if (RB_FL_TEST_RAW(orig, FL_FREEZE | STR_CHILLED) == FL_FREEZE) return orig;
1572 return str_new_frozen(rb_obj_class(orig), orig);
1573}
1574
1575static VALUE
1576rb_str_new_frozen_String(VALUE orig)
1577{
1578 if (OBJ_FROZEN(orig) && rb_obj_class(orig) == rb_cString) return orig;
1579 return str_new_frozen(rb_cString, orig);
1580}
1581
1582
1583VALUE
1584rb_str_frozen_bare_string(VALUE orig)
1585{
1586 if (RB_LIKELY(BARE_STRING_P(orig) && OBJ_FROZEN_RAW(orig))) return orig;
1587 return str_new_frozen(rb_cString, orig);
1588}
1589
1590VALUE
1591rb_str_tmp_frozen_acquire(VALUE orig)
1592{
1593 if (OBJ_FROZEN_RAW(orig)) return orig;
1594 return str_new_frozen_buffer(0, orig, FALSE);
1595}
1596
1597VALUE
1599{
1600 if (OBJ_FROZEN_RAW(orig) && !STR_EMBED_P(orig)) return orig;
1601 if (STR_SHARED_P(orig) && !STR_EMBED_P(RSTRING(orig)->as.heap.aux.shared)) return rb_str_tmp_frozen_acquire(orig);
1602
1603 VALUE str = str_alloc_heap(0);
1604 OBJ_FREEZE(str);
1605 /* Always set the STR_SHARED_ROOT to ensure it does not get re-embedded. */
1606 FL_SET(str, STR_SHARED_ROOT);
1607
1608 size_t capa = str_capacity(orig, TERM_LEN(orig));
1609
1610 /* If the string is embedded then we want to create a copy that is heap
1611 * allocated. If the string is shared then the shared root must be
1612 * embedded, so we want to create a copy. If the string is a shared root
1613 * then it must be embedded, so we want to create a copy. */
1614 if (STR_EMBED_P(orig) || FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT | RSTRING_FSTR)) {
1615 RSTRING(str)->as.heap.ptr = rb_xmalloc_mul_add_mul(sizeof(char), capa, sizeof(char), TERM_LEN(orig));
1616 memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), capa);
1617 }
1618 else {
1619 /* orig must be heap allocated and not shared, so we can safely transfer
1620 * the pointer to str. */
1621 RSTRING(str)->as.heap.ptr = RSTRING(orig)->as.heap.ptr;
1622 RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1623 RBASIC(orig)->flags &= ~STR_NOFREE;
1624 STR_SET_SHARED(orig, str);
1625 /* str was just allocated here, so orig is its only child and it is
1626 * safe for rb_str_tmp_frozen_release to give the buffer back. */
1627 FL_UNSET_RAW(str, STR_BORROWED);
1628 if (RB_OBJ_SHAREABLE_P(orig)) {
1630 RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
1631 }
1632 }
1633
1634 RSTRING(str)->len = RSTRING(orig)->len;
1635 RSTRING(str)->as.heap.aux.capa = capa + (TERM_LEN(orig) - TERM_LEN(str));
1636
1637 return str;
1638}
1639
1640void
1642{
1643 rb_str_tmp_frozen_release(orig, tmp);
1644}
1645
1646void
1647rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
1648{
1649 if (RBASIC_CLASS(tmp) != 0)
1650 return;
1651
1652 if (STR_EMBED_P(tmp)) {
1654 }
1655 else if (FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_SHARED &&
1656 !OBJ_FROZEN_RAW(orig)) {
1657 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1658
1659 if (shared == tmp && !FL_TEST_RAW(tmp, STR_BORROWED)) {
1660 RUBY_ASSERT(RSTRING(orig)->as.heap.ptr == RSTRING(tmp)->as.heap.ptr);
1661 RUBY_ASSERT(RSTRING_LEN(orig) == RSTRING_LEN(tmp));
1662
1663 /* Unshare orig since the root (tmp) only has this one child. */
1664 FL_UNSET_RAW(orig, STR_SHARED);
1665 RSTRING(orig)->as.heap.aux.capa = RSTRING(tmp)->as.heap.aux.capa + TERM_LEN(tmp) - TERM_LEN(orig);
1666 RBASIC(orig)->flags |= RBASIC(tmp)->flags & STR_NOFREE;
1668
1669 /* Make tmp embedded and empty so it is safe for sweeping. */
1670 STR_SET_EMBED(tmp);
1671 STR_SET_LEN(tmp, 0);
1672 }
1673 }
1674}
1675
1676static VALUE
1677str_new_frozen(VALUE klass, VALUE orig)
1678{
1679 return str_new_frozen_buffer(klass, orig, TRUE);
1680}
1681
1682/* Transfers ownership of orig's buffer to a new shared root string.
1683 * termlen is the terminator length of the returned string, which may differ
1684 * from orig's terminator length when the caller does not copy the encoding.
1685 * The capacity is stored without the terminator, so it must be adjusted for
1686 * the difference to keep the buffer size (capa + termlen) unchanged. */
1687static VALUE
1688heap_str_make_shared(VALUE klass, VALUE orig, int termlen)
1689{
1690 RUBY_ASSERT(!STR_EMBED_P(orig));
1691 RUBY_ASSERT(!STR_SHARED_P(orig));
1693
1694 VALUE str = str_alloc_heap(klass);
1695 STR_SET_LEN(str, RSTRING_LEN(orig));
1696 RSTRING(str)->as.heap.ptr = RSTRING_PTR(orig);
1697 RSTRING(str)->as.heap.aux.capa = RSTRING(orig)->as.heap.aux.capa + TERM_LEN(orig) - termlen;
1698 RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1699 RBASIC(orig)->flags &= ~STR_NOFREE;
1700 STR_SET_SHARED(orig, str);
1701 if (klass == 0)
1702 FL_UNSET_RAW(str, STR_BORROWED);
1703 return str;
1704}
1705
1706static VALUE
1707str_new_frozen_buffer(VALUE klass, VALUE orig, int copy_encoding)
1708{
1709 VALUE str;
1710
1711 rb_len_t len = RSTRING_LEN(orig);
1712 rb_encoding *enc = copy_encoding ? STR_ENC_GET(orig) : rb_ascii8bit_encoding();
1713 int termlen = copy_encoding ? TERM_LEN(orig) : 1;
1714
1715 if (STR_EMBED_P(orig) || STR_EMBEDDABLE_P(len, termlen)) {
1716 str = str_enc_new(klass, RSTRING_PTR(orig), len, enc);
1717 RUBY_ASSERT(STR_EMBED_P(str));
1718 }
1719 else {
1720 if (FL_TEST_RAW(orig, STR_SHARED)) {
1721 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1722 rb_len_t ofs = RSTRING(orig)->as.heap.ptr - RSTRING_PTR(shared);
1723 rb_len_t rest = RSTRING_LEN(shared) - ofs - RSTRING_LEN(orig);
1724 RUBY_ASSERT(ofs >= 0);
1725 RUBY_ASSERT(rest >= 0);
1726 RUBY_ASSERT(ofs + rest <= RSTRING_LEN(shared));
1728
1729 if ((ofs > 0) || (rest > 0) ||
1730 (klass != RBASIC(shared)->klass) ||
1731 ENCODING_GET(shared) != ENCODING_GET(orig)) {
1732 str = str_new_shared(klass, shared);
1733 RUBY_ASSERT(!STR_EMBED_P(str));
1734 RSTRING(str)->as.heap.ptr += ofs;
1735 STR_SET_LEN(str, RSTRING_LEN(str) - (ofs + rest));
1736 }
1737 else {
1738 if (RBASIC_CLASS(shared) == 0)
1739 FL_SET_RAW(shared, STR_BORROWED);
1740 return shared;
1741 }
1742 }
1743 else if (STR_EMBEDDABLE_P(RSTRING_LEN(orig), TERM_LEN(orig))) {
1744 str = str_alloc_embed(klass, RSTRING_LEN(orig) + TERM_LEN(orig));
1745 STR_SET_EMBED(str);
1746 memcpy(RSTRING_PTR(str), RSTRING_PTR(orig), RSTRING_LEN(orig));
1747 STR_SET_LEN(str, RSTRING_LEN(orig));
1748 ENC_CODERANGE_SET(str, ENC_CODERANGE(orig));
1749 TERM_FILL(RSTRING_END(str), TERM_LEN(orig));
1750 }
1751 else {
1752 if (RB_OBJ_SHAREABLE_P(orig)) {
1753 str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
1754 }
1755 else {
1756 str = heap_str_make_shared(klass, orig, termlen);
1757 }
1758 }
1759 }
1760
1761 if (copy_encoding) rb_enc_cr_str_exact_copy(str, orig);
1762 OBJ_FREEZE(str);
1763 return str;
1764}
1765
1766VALUE
1768{
1769 return str_enc_new(rb_obj_class(obj), ptr, len, STR_ENC_GET(obj));
1770}
1771
1772static VALUE
1773str_new_empty_String(VALUE str)
1774{
1775 VALUE v = rb_str_new(0, 0);
1776 rb_enc_copy(v, str);
1777 return v;
1778}
1779
1780#define STR_BUF_MIN_SIZE 63
1781
1782VALUE
1784{
1785 if (STR_EMBEDDABLE_P(capa, 1)) {
1786 return str_alloc_embed(rb_cString, capa + 1);
1787 }
1788
1789 VALUE str = str_alloc_heap(rb_cString);
1790
1791 RSTRING(str)->as.heap.aux.capa = capa;
1792 RSTRING(str)->as.heap.ptr = ALLOC_N(char, (size_t)capa + 1);
1793 RSTRING(str)->as.heap.ptr[0] = '\0';
1794
1795 return str;
1796}
1797
1798VALUE
1800{
1801 VALUE str;
1802 rb_len_t len = strlen(ptr);
1803
1804 str = rb_str_buf_new(len);
1805 rb_str_buf_cat(str, ptr, len);
1806
1807 return str;
1808}
1809
1810VALUE
1812{
1813 return str_new(0, 0, len);
1814}
1815
1816void
1818{
1819 if (STR_EMBED_P(str)) {
1820 RB_DEBUG_COUNTER_INC(obj_str_embed);
1821 }
1822 else if (FL_TEST(str, STR_SHARED | STR_NOFREE)) {
1823 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_SHARED));
1824 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_NOFREE));
1825 }
1826 else {
1827 RB_DEBUG_COUNTER_INC(obj_str_ptr);
1828 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
1829 }
1830}
1831
1832size_t
1833rb_str_memsize(VALUE str)
1834{
1835 if (FL_TEST(str, STR_NOEMBED|STR_SHARED|STR_NOFREE) == STR_NOEMBED) {
1836 return STR_HEAP_SIZE(str);
1837 }
1838 else {
1839 return 0;
1840 }
1841}
1842
1843VALUE
1845{
1846 return rb_convert_type_with_id(str, T_STRING, "String", idTo_str);
1847}
1848
1849static inline void str_discard(VALUE str);
1850static void str_shared_replace(VALUE str, VALUE str2);
1851
1852void
1854{
1855 if (str != str2) str_shared_replace(str, str2);
1856}
1857
1858static void
1859str_shared_replace(VALUE str, VALUE str2)
1860{
1861 rb_encoding *enc;
1862 int cr;
1863 int termlen;
1864
1865 RUBY_ASSERT(str2 != str);
1866 enc = STR_ENC_GET(str2);
1867 cr = ENC_CODERANGE(str2);
1868 str_discard(str);
1869 termlen = rb_enc_mbminlen(enc);
1870
1871 STR_SET_LEN(str, RSTRING_LEN(str2));
1872
1873 if (str_embed_capa(str) >= RSTRING_LEN(str2) + termlen) {
1874 STR_SET_EMBED(str);
1875 memcpy(RSTRING_PTR(str), RSTRING_PTR(str2), (size_t)RSTRING_LEN(str2) + termlen);
1876 }
1877 else {
1878 if (STR_EMBED_P(str2)) {
1879 RUBY_ASSERT(!FL_TEST(str2, STR_SHARED));
1880 rb_len_t len = RSTRING_LEN(str2);
1881 RUBY_ASSERT(len + termlen <= str_embed_capa(str2));
1882
1883 char *new_ptr = ALLOC_N(char, len + termlen);
1884 memcpy(new_ptr, RSTRING(str2)->as.embed.ary, len + termlen);
1885 RSTRING(str2)->as.heap.ptr = new_ptr;
1886 STR_SET_LEN(str2, len);
1887 RSTRING(str2)->as.heap.aux.capa = len;
1888 STR_SET_NOEMBED(str2);
1889 }
1890
1891 STR_SET_NOEMBED(str);
1892 FL_UNSET(str, STR_SHARED);
1893 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1894
1895 if (FL_TEST(str2, STR_SHARED)) {
1896 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1897 STR_SET_SHARED(str, shared);
1898 }
1899 else {
1900 RSTRING(str)->as.heap.aux.capa = RSTRING(str2)->as.heap.aux.capa;
1901 }
1902
1903 /* abandon str2 */
1904 STR_SET_EMBED(str2);
1905 RSTRING_PTR(str2)[0] = 0;
1906 STR_SET_LEN(str2, 0);
1907 }
1908
1909 // We used str2's termlen above so we set enc raw
1910 // to avoid adjusting it based on str1's old enc.
1911 rb_enc_raw_set(str, enc);
1912 ENC_CODERANGE_SET(str, cr);
1913}
1914
1915VALUE
1917{
1918 VALUE str;
1919
1920 if (RB_TYPE_P(obj, T_STRING)) {
1921 return obj;
1922 }
1923 str = rb_funcall(obj, idTo_s, 0);
1924 return rb_obj_as_string_result(str, obj);
1925}
1926
1927VALUE
1928rb_obj_as_string_result(VALUE str, VALUE obj)
1929{
1930 if (!RB_TYPE_P(str, T_STRING))
1931 return rb_any_to_s(obj);
1932 return str;
1933}
1934
1935static VALUE
1936str_replace(VALUE str, VALUE str2)
1937{
1938 rb_len_t len;
1939
1940 len = RSTRING_LEN(str2);
1941 if (STR_SHARED_P(str2)) {
1942 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1944 STR_SET_NOEMBED(str);
1945 STR_SET_LEN(str, len);
1946 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1947 STR_SET_SHARED(str, shared);
1948 rb_enc_cr_str_exact_copy(str, str2);
1949 }
1950 else {
1951 str_replace_shared(str, str2);
1952 }
1953
1954 return str;
1955}
1956
1957static inline VALUE
1958ec_str_alloc_embed(struct rb_execution_context_struct *ec, VALUE klass, size_t capa)
1959{
1960 size_t size = rb_str_embed_size(capa, 0);
1961 RUBY_ASSERT(size > 0);
1962 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
1963
1964 EC_NEWOBJ_OF(str, struct RString, klass, T_STRING, size, ec);
1965
1966 str->len = 0;
1967
1968 return (VALUE)str;
1969}
1970
1971static inline VALUE
1972ec_str_alloc_heap(struct rb_execution_context_struct *ec, VALUE klass)
1973{
1974 EC_NEWOBJ_OF(str, struct RString, klass, T_STRING | STR_NOEMBED, sizeof(struct RString), ec);
1975
1976 str->as.heap.aux.capa = 0;
1977 str->as.heap.ptr = NULL;
1978
1979 return (VALUE)str;
1980}
1981
1982static inline void
1983str_duplicate_setup_encoding(VALUE str, VALUE dup, VALUE flags)
1984{
1985 int encidx = 0;
1986 if ((flags & ENCODING_MASK) == (ENCODING_INLINE_MAX<<ENCODING_SHIFT)) {
1987 encidx = rb_enc_get_index(str);
1988 flags &= ~ENCODING_MASK;
1989 }
1990 FL_SET_RAW(dup, flags & ~FL_FREEZE);
1991 if (encidx) rb_enc_associate_index(dup, encidx);
1992}
1993
1994static const VALUE flag_mask = ENC_CODERANGE_MASK | ENCODING_MASK | FL_FREEZE;
1995
1996static inline void
1997str_duplicate_setup_embed(VALUE klass, VALUE str, VALUE dup)
1998{
1999 VALUE flags = FL_TEST_RAW(str, flag_mask);
2000 rb_len_t len = RSTRING_LEN(str);
2001
2002 RUBY_ASSERT(STR_EMBED_P(dup));
2003 RUBY_ASSERT(str_embed_capa(dup) >= len + TERM_LEN(str));
2004 MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + TERM_LEN(str));
2005 STR_SET_LEN(dup, RSTRING_LEN(str));
2006 str_duplicate_setup_encoding(str, dup, flags);
2007}
2008
2009static inline void
2010str_duplicate_setup_heap(VALUE klass, VALUE str, VALUE dup)
2011{
2012 VALUE flags = FL_TEST_RAW(str, flag_mask);
2013 VALUE root = str;
2014 if (FL_TEST_RAW(str, STR_SHARED)) {
2015 root = RSTRING(str)->as.heap.aux.shared;
2016 }
2017 else if (UNLIKELY(!OBJ_FROZEN_RAW(str))) {
2018 root = str = str_new_frozen(klass, str);
2019 flags = FL_TEST_RAW(str, flag_mask);
2020 }
2021 RUBY_ASSERT(!STR_SHARED_P(root));
2023
2024 RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
2025 FL_SET_RAW(dup, RSTRING_NOEMBED);
2026 STR_SET_SHARED(dup, root);
2027 flags |= RSTRING_NOEMBED | STR_SHARED;
2028
2029 STR_SET_LEN(dup, RSTRING_LEN(str));
2030 str_duplicate_setup_encoding(str, dup, flags);
2031}
2032
2033static inline VALUE
2034str_duplicate(VALUE klass, VALUE str)
2035{
2036 VALUE dup;
2037 if (STR_EMBED_P(str) && rb_str_embed_size(RSTRING_LEN(str), 1) <= STR_COPY_MAX_EMBED_SIZE) {
2038 dup = str_alloc_embed(klass, RSTRING_LEN(str) + TERM_LEN(str));
2039
2040 str_duplicate_setup_embed(klass, str, dup);
2041 }
2042 else {
2043 dup = str_alloc_heap(klass);
2044
2045 str_duplicate_setup_heap(klass, str, dup);
2046 }
2047
2048 return dup;
2049}
2050
2051VALUE
2053{
2054 return str_duplicate(rb_obj_class(str), str);
2055}
2056
2057/* :nodoc: */
2058VALUE
2059rb_str_dup_m(VALUE str)
2060{
2061 if (LIKELY(BARE_STRING_P(str))) {
2062 return str_duplicate(rb_cString, str);
2063 }
2064 else {
2065 return rb_obj_dup(str);
2066 }
2067}
2068
2069VALUE
2071{
2072 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2073 return str_duplicate(rb_cString, str);
2074}
2075
2076VALUE
2077rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled)
2078{
2079 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2080 VALUE new_str, klass = rb_cString;
2081
2082 if (!(chilled && RTEST(rb_ivar_defined(str, id_debug_created_info))) && STR_EMBED_P(str)) {
2083 new_str = ec_str_alloc_embed(ec, klass, RSTRING_LEN(str) + TERM_LEN(str));
2084 str_duplicate_setup_embed(klass, str, new_str);
2085 }
2086 else {
2087 new_str = ec_str_alloc_heap(ec, klass);
2088 str_duplicate_setup_heap(klass, str, new_str);
2089 }
2090 if (chilled) {
2091 FL_SET_RAW(new_str, STR_CHILLED);
2092 }
2093 return new_str;
2094}
2095
2096#if USE_ZJIT
2097bool
2098rb_zjit_str_resurrect_fastpath(VALUE str, bool chilled, size_t *size_out,
2099 VALUE *flags_out,
2100 rb_len_t *len_out, size_t *byte_size_out)
2101{
2102 if (chilled && RTEST(rb_ivar_defined(str, id_debug_created_info))) return false;
2103
2104 if (!STR_EMBED_P(str)) return false;
2105
2106 rb_len_t len = RSTRING_LEN(str);
2107 rb_len_t termlen = TERM_LEN(str);
2108 size_t size = rb_str_embed_size(len + termlen, 0);
2109 if (!rb_gc_size_allocatable_p(size)) return false;
2110
2111 VALUE flags = FL_TEST_RAW(str, flag_mask);
2112
2113 if ((flags & ENCODING_MASK) == ((VALUE)ENCODING_INLINE_MAX << ENCODING_SHIFT)) {
2114 return false;
2115 }
2116
2117 flags &= ~FL_FREEZE;
2118 flags |= T_STRING;
2119 if (chilled) flags |= STR_CHILLED;
2120
2121 *size_out = size;
2122 *flags_out = flags;
2123 *len_out = len;
2124 *byte_size_out = (size_t)(len + termlen);
2125 return true;
2126}
2127#endif
2128
2129VALUE
2130rb_str_with_debug_created_info(VALUE str, VALUE path, int line)
2131{
2132 VALUE debug_info = rb_ary_new_from_args(2, path, INT2FIX(line));
2133 if (OBJ_FROZEN_RAW(str)) str = rb_str_dup(str);
2134 rb_ivar_set(str, id_debug_created_info, rb_ary_freeze(debug_info));
2135 FL_SET_RAW(str, STR_CHILLED);
2136 return rb_str_freeze(str);
2137}
2138
2139/*
2140 * The documentation block below uses an include (instead of inline text)
2141 * because the included text has non-ASCII characters (which are not allowed in a C file).
2142 */
2143
2144/*
2145 *
2146 * call-seq:
2147 * String.new(string = ''.encode(Encoding::ASCII_8BIT) , **options) -> new_string
2148 *
2149 * :include: doc/string/new.rdoc
2150 *
2151 */
2152
2153static VALUE
2154rb_str_init(int argc, VALUE *argv, VALUE str)
2155{
2156 static ID keyword_ids[2];
2157 VALUE orig, opt, venc, vcapa;
2158 VALUE kwargs[2];
2159 rb_encoding *enc = 0;
2160 int n;
2161
2162 if (!keyword_ids[0]) {
2163 keyword_ids[0] = rb_id_encoding();
2164 CONST_ID(keyword_ids[1], "capacity");
2165 }
2166
2167 n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2168 if (!NIL_P(opt)) {
2169 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2170 venc = kwargs[0];
2171 vcapa = kwargs[1];
2172 if (!NIL_OR_UNDEF_P(venc)) {
2173 enc = rb_to_encoding(venc);
2174 }
2175 if (!NIL_OR_UNDEF_P(vcapa)) {
2176 rb_len_t capa = NUM2LEN(vcapa);
2177 rb_len_t len = 0;
2178 int termlen;
2179
2180 if (capa < STR_BUF_MIN_SIZE) {
2181 capa = STR_BUF_MIN_SIZE;
2182 }
2183 if (n == 1) {
2184 StringValue(orig);
2185 len = RSTRING_LEN(orig);
2186 if (capa < len) {
2187 capa = len;
2188 }
2189 if (orig == str) n = 0;
2190 }
2191 termlen = enc ? rb_enc_mbminlen(enc) : TERM_LEN(n == 1 ? orig : str);
2192 str_modifiable(str);
2193 if (STR_EMBED_P(str) || FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2194 /* make noembed always */
2195 const size_t size = (size_t)capa + termlen;
2196 const char *const old_ptr = RSTRING_PTR(str);
2197 const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
2198 char *new_ptr = ALLOC_N(char, size);
2199 if (STR_EMBED_P(str)) RUBY_ASSERT((rb_len_t)osize <= str_embed_capa(str));
2200 memcpy(new_ptr, old_ptr, osize < size ? osize : size);
2201 FL_UNSET_RAW(str, STR_SHARED|STR_NOFREE);
2202 RSTRING(str)->as.heap.ptr = new_ptr;
2203 }
2204 else if (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
2205 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
2206 (size_t)capa + termlen, STR_HEAP_SIZE(str));
2207 }
2208 STR_SET_LEN(str, len);
2209 TERM_FILL(&RSTRING(str)->as.heap.ptr[len], termlen);
2210 if (n == 1) {
2211 memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), len);
2212 if (!enc || rb_enc_get(orig) == enc) {
2213 rb_enc_cr_str_exact_copy(str, orig);
2214 enc = 0;
2215 }
2216 }
2217 FL_SET(str, STR_NOEMBED);
2218 RSTRING(str)->as.heap.aux.capa = capa;
2219 }
2220 else if (n == 1) {
2221 rb_str_replace(str, orig);
2222 }
2223 if (enc) {
2224 str_modifiable(str);
2225 if (NIL_OR_UNDEF_P(vcapa)) {
2226 rb_enc_associate(str, enc);
2227 }
2228 else {
2229 /* the buffer is already sized for enc's terminator */
2230 rb_enc_raw_set(str, enc);
2231 }
2233 }
2234 }
2235 else if (n == 1) {
2236 rb_str_replace(str, orig);
2237 }
2238 return str;
2239}
2240
2241/* :nodoc: */
2242static VALUE
2243rb_str_s_new(int argc, VALUE *argv, VALUE klass)
2244{
2245 if (klass != rb_cString) {
2246 return rb_class_new_instance_pass_kw(argc, argv, klass);
2247 }
2248
2249 static ID keyword_ids[2];
2250 VALUE orig, opt, encoding = Qnil, capacity = Qnil;
2251 VALUE kwargs[2];
2252 rb_encoding *enc = NULL;
2253
2254 int n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2255 if (NIL_P(opt)) {
2256 return rb_class_new_instance_pass_kw(argc, argv, klass);
2257 }
2258
2259 keyword_ids[0] = rb_id_encoding();
2260 CONST_ID(keyword_ids[1], "capacity");
2261 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2262 encoding = kwargs[0];
2263 capacity = kwargs[1];
2264
2265 if (n == 1) {
2266 orig = StringValue(orig);
2267 }
2268 else {
2269 orig = Qnil;
2270 }
2271
2272 if (UNDEF_P(encoding)) {
2273 if (!NIL_P(orig)) {
2274 encoding = rb_obj_encoding(orig);
2275 }
2276 }
2277
2278 if (!UNDEF_P(encoding)) {
2279 enc = rb_to_encoding(encoding);
2280 }
2281
2282 // If capacity is nil, we're basically just duping `orig`.
2283 if (UNDEF_P(capacity)) {
2284 if (NIL_P(orig)) {
2285 VALUE empty_str = str_new(klass, "", 0);
2286 if (enc) {
2287 rb_enc_associate(empty_str, enc);
2288 }
2289 return empty_str;
2290 }
2291 VALUE copy = str_duplicate(klass, orig);
2292 rb_enc_associate(copy, enc);
2293 ENC_CODERANGE_CLEAR(copy);
2294 return copy;
2295 }
2296
2297 rb_len_t capa = 0;
2298 capa = NUM2LEN(capacity);
2299 if (capa < 0) {
2300 capa = 0;
2301 }
2302
2303 if (!NIL_P(orig)) {
2304 rb_len_t orig_capa = rb_str_capacity(orig);
2305 if (orig_capa > capa) {
2306 capa = orig_capa;
2307 }
2308 }
2309
2310 VALUE str = str_enc_new(klass, NULL, capa, enc);
2311 STR_SET_LEN(str, 0);
2312 TERM_FILL(RSTRING_PTR(str), enc ? rb_enc_mbmaxlen(enc) : 1);
2313
2314 if (!NIL_P(orig)) {
2315 rb_str_buf_append(str, orig);
2316 }
2317
2318 return str;
2319}
2320
2321#ifdef NONASCII_MASK
2322#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2323
2324/*
2325 * UTF-8 leading bytes have either 0xxxxxxx or 11xxxxxx
2326 * bit representation. (see https://en.wikipedia.org/wiki/UTF-8)
2327 * Therefore, the following pseudocode can detect UTF-8 leading bytes.
2328 *
2329 * if (!(byte & 0x80))
2330 * byte |= 0x40; // turn on bit6
2331 * return ((byte>>6) & 1); // bit6 represent whether this byte is leading or not.
2332 *
2333 * This function calculates whether a byte is leading or not for all bytes
2334 * in the argument word by concurrently using the above logic, and then
2335 * adds up the number of leading bytes in the word.
2336 */
2337static inline uintptr_t
2338count_utf8_lead_bytes_with_word(const uintptr_t *s)
2339{
2340 uintptr_t d = *s;
2341
2342 /* Transform so that bit0 indicates whether we have a UTF-8 leading byte or not. */
2343 d = (d>>6) | (~d>>7);
2344 d &= NONASCII_MASK >> 7;
2345
2346 /* Gather all bytes. */
2347#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2348 /* use only if it can use POPCNT */
2349 return rb_popcount_intptr(d);
2350#else
2351 d += (d>>8);
2352 d += (d>>16);
2353# if SIZEOF_VOIDP == 8
2354 d += (d>>32);
2355# endif
2356 return (d&0xF);
2357#endif
2358}
2359#endif
2360
2361static inline rb_len_t
2362enc_strlen(const char *p, const char *e, rb_encoding *enc, int cr)
2363{
2364 rb_len_t c;
2365 const char *q;
2366
2367 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2368 rb_len_t diff = (rb_len_t)(e - p);
2369 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2370 }
2371#ifdef NONASCII_MASK
2372 else if (cr == ENC_CODERANGE_VALID && enc == rb_utf8_encoding()) {
2373 uintptr_t len = 0;
2374 if ((int)sizeof(uintptr_t) * 2 < e - p) {
2375 const uintptr_t *s, *t;
2376 const uintptr_t lowbits = sizeof(uintptr_t) - 1;
2377 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2378 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
2379 while (p < (const char *)s) {
2380 if (is_utf8_lead_byte(*p)) len++;
2381 p++;
2382 }
2383 while (s < t) {
2384 len += count_utf8_lead_bytes_with_word(s);
2385 s++;
2386 }
2387 p = (const char *)s;
2388 }
2389 while (p < e) {
2390 if (is_utf8_lead_byte(*p)) len++;
2391 p++;
2392 }
2393 return (rb_len_t)len;
2394 }
2395#endif
2396 else if (rb_enc_asciicompat(enc)) {
2397 c = 0;
2398 if (ENC_CODERANGE_CLEAN_P(cr)) {
2399 while (p < e) {
2400 q = search_nonascii(p, e);
2401 if (!q)
2402 return c + (e - p);
2403 c += q - p;
2404 p = q;
2405 p += rb_enc_fast_mbclen(p, e, enc);
2406 c++;
2407 }
2408 }
2409 else {
2410 while (p < e) {
2411 q = search_nonascii(p, e);
2412 if (!q)
2413 return c + (e - p);
2414 c += q - p;
2415 p = q;
2416 p += rb_enc_mbclen(p, e, enc);
2417 c++;
2418 }
2419 }
2420 return c;
2421 }
2422
2423 for (c=0; p<e; c++) {
2424 p += rb_enc_mbclen(p, e, enc);
2425 }
2426 return c;
2427}
2428
2430rb_enc_strlen(const char *p, const char *e, rb_encoding *enc)
2431{
2432 return enc_strlen(p, e, enc, ENC_CODERANGE_UNKNOWN);
2433}
2434
2435/* To get strlen with cr
2436 * Note that given cr is not used.
2437 */
2439rb_enc_strlen_cr(const char *p, const char *e, rb_encoding *enc, int *cr)
2440{
2441 rb_len_t c;
2442 const char *q;
2443 int ret;
2444
2445 *cr = 0;
2446 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2447 rb_len_t diff = (rb_len_t)(e - p);
2448 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2449 }
2450 else if (rb_enc_asciicompat(enc)) {
2451 c = 0;
2452 while (p < e) {
2453 q = search_nonascii(p, e);
2454 if (!q) {
2455 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2456 return c + (e - p);
2457 }
2458 c += q - p;
2459 p = q;
2460 ret = rb_enc_precise_mbclen(p, e, enc);
2461 if (MBCLEN_CHARFOUND_P(ret)) {
2462 *cr |= ENC_CODERANGE_VALID;
2463 p += MBCLEN_CHARFOUND_LEN(ret);
2464 }
2465 else {
2467 p++;
2468 }
2469 c++;
2470 }
2471 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2472 return c;
2473 }
2474
2475 for (c=0; p<e; c++) {
2476 ret = rb_enc_precise_mbclen(p, e, enc);
2477 if (MBCLEN_CHARFOUND_P(ret)) {
2478 *cr |= ENC_CODERANGE_VALID;
2479 p += MBCLEN_CHARFOUND_LEN(ret);
2480 }
2481 else {
2483 if (p + rb_enc_mbminlen(enc) <= e)
2484 p += rb_enc_mbminlen(enc);
2485 else
2486 p = e;
2487 }
2488 }
2489 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2490 return c;
2491}
2492
2493/* enc must be str's enc or rb_enc_check(str, str2) */
2494static rb_len_t
2495str_strlen(VALUE str, rb_encoding *enc)
2496{
2497 const char *p, *e;
2498 int cr;
2499
2500 if (single_byte_optimizable(str)) return RSTRING_LEN(str);
2501 if (!enc) enc = STR_ENC_GET(str);
2502 p = RSTRING_PTR(str);
2503 e = RSTRING_END(str);
2504 cr = ENC_CODERANGE(str);
2505
2506 if (cr == ENC_CODERANGE_UNKNOWN) {
2507 rb_len_t n = rb_enc_strlen_cr(p, e, enc, &cr);
2508 if (cr) ENC_CODERANGE_SET(str, cr);
2509 return n;
2510 }
2511 else {
2512 return enc_strlen(p, e, enc, cr);
2513 }
2514}
2515
2518{
2519 return str_strlen(str, NULL);
2520}
2521
2522/*
2523 * call-seq:
2524 * length -> integer
2525 *
2526 * :include: doc/string/length.rdoc
2527 *
2528 */
2529
2530VALUE
2532{
2533 return LEN2NUM(str_strlen(str, NULL));
2534}
2535
2536/*
2537 * call-seq:
2538 * bytesize -> integer
2539 *
2540 * :include: doc/string/bytesize.rdoc
2541 *
2542 */
2543
2544VALUE
2545rb_str_bytesize(VALUE str)
2546{
2547 return LEN2NUM(RSTRING_LEN(str));
2548}
2549
2550/*
2551 * call-seq:
2552 * empty? -> true or false
2553 *
2554 * Returns whether the length of +self+ is zero:
2555 *
2556 * 'hello'.empty? # => false
2557 * ' '.empty? # => false
2558 * ''.empty? # => true
2559 *
2560 * Related: see {Querying}[rdoc-ref:String@Querying].
2561 */
2562
2563static VALUE
2564rb_str_empty(VALUE str)
2565{
2566 return RBOOL(RSTRING_LEN(str) == 0);
2567}
2568
2569/*
2570 * call-seq:
2571 * self + other_string -> new_string
2572 *
2573 * Returns a new string containing +other_string+ concatenated to +self+:
2574 *
2575 * 'Hello from ' + self.to_s # => "Hello from main"
2576 *
2577 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2578 */
2579
2580VALUE
2582{
2583 VALUE str3;
2584 rb_encoding *enc;
2585 const char *ptr1, *ptr2;
2586 char *ptr3;
2587 rb_len_t len1, len2;
2588 int termlen;
2589
2590 StringValue(str2);
2591 enc = rb_enc_check_str(str1, str2);
2592 RSTRING_GETMEM(str1, ptr1, len1);
2593 RSTRING_GETMEM(str2, ptr2, len2);
2594 termlen = rb_enc_mbminlen(enc);
2595 if (len1 > RB_LEN_MAX - len2) {
2596 rb_raise(rb_eArgError, "string size too big");
2597 }
2598 str3 = str_enc_new(rb_cString, 0, len1+len2, enc);
2599 ptr3 = RSTRING_PTR(str3);
2600 memcpy(ptr3, ptr1, len1);
2601 memcpy(ptr3+len1, ptr2, len2);
2602 TERM_FILL(&ptr3[len1+len2], termlen);
2603
2604 ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
2606 RB_GC_GUARD(str1);
2607 RB_GC_GUARD(str2);
2608 return str3;
2609}
2610
2611/* A variant of rb_str_plus that does not raise but return Qundef instead. */
2612VALUE
2613rb_str_opt_plus(VALUE str1, VALUE str2)
2614{
2617 rb_len_t len1, len2;
2618 MAYBE_UNUSED(char) *ptr1, *ptr2;
2619 RSTRING_GETMEM(str1, ptr1, len1);
2620 RSTRING_GETMEM(str2, ptr2, len2);
2621 int enc1 = rb_enc_get_index(str1);
2622 int enc2 = rb_enc_get_index(str2);
2623
2624 if (enc1 < 0) {
2625 return Qundef;
2626 }
2627 else if (enc2 < 0) {
2628 return Qundef;
2629 }
2630 else if (enc1 != enc2) {
2631 return Qundef;
2632 }
2633 else if (len1 > RB_LEN_MAX - len2) {
2634 return Qundef;
2635 }
2636 else {
2637 return rb_str_plus(str1, str2);
2638 }
2639
2640}
2641
2642/*
2643 * call-seq:
2644 * self * n -> new_string
2645 *
2646 * Returns a new string containing +n+ copies of +self+:
2647 *
2648 * 'Ho!' * 3 # => "Ho!Ho!Ho!"
2649 * 'No!' * 0 # => ""
2650 *
2651 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2652 */
2653
2654VALUE
2656{
2657 VALUE str2;
2658 rb_len_t n, len;
2659 char *ptr2;
2660 int termlen;
2661
2662 if (times == INT2FIX(1)) {
2663 return str_duplicate(rb_cString, str);
2664 }
2665 if (times == INT2FIX(0)) {
2666 str2 = str_alloc_embed(rb_cString, 0);
2667 rb_enc_copy(str2, str);
2668 return str2;
2669 }
2670 len = NUM2LEN(times);
2671 if (len < 0) {
2672 rb_raise(rb_eArgError, "negative argument");
2673 }
2674 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2675 if (STR_EMBEDDABLE_P(len, 1)) {
2676 str2 = str_alloc_embed(rb_cString, len + 1);
2677 memset(RSTRING_PTR(str2), 0, len + 1);
2678 }
2679 else {
2680 str2 = str_alloc_heap(rb_cString);
2681 RSTRING(str2)->as.heap.aux.capa = len;
2682 RSTRING(str2)->as.heap.ptr = ZALLOC_N(char, (size_t)len + 1);
2683 }
2684 STR_SET_LEN(str2, len);
2685 rb_enc_copy(str2, str);
2686 return str2;
2687 }
2688 if (len && RB_LEN_MAX/len < RSTRING_LEN(str)) {
2689 rb_raise(rb_eArgError, "argument too big");
2690 }
2691
2692 len *= RSTRING_LEN(str);
2693 termlen = TERM_LEN(str);
2694 str2 = str_enc_new(rb_cString, 0, len, STR_ENC_GET(str));
2695 ptr2 = RSTRING_PTR(str2);
2696 if (len) {
2697 n = RSTRING_LEN(str);
2698 memcpy(ptr2, RSTRING_PTR(str), n);
2699 while (n <= len/2) {
2700 memcpy(ptr2 + n, ptr2, n);
2701 n *= 2;
2702 }
2703 memcpy(ptr2 + n, ptr2, len-n);
2704 }
2705 STR_SET_LEN(str2, len);
2706 TERM_FILL(&ptr2[len], termlen);
2707 rb_enc_cr_str_copy_for_substr(str2, str);
2708
2709 return str2;
2710}
2711
2712/*
2713 * call-seq:
2714 * self % object -> new_string
2715 *
2716 * Returns the result of formatting +object+ into the format specifications
2717 * contained in +self+
2718 * (see {Format Specifications}[rdoc-ref:language/format_specifications.rdoc]):
2719 *
2720 * '%05d' % 123 # => "00123"
2721 *
2722 * If +self+ contains multiple format specifications,
2723 * +object+ must be an array or hash containing the objects to be formatted:
2724 *
2725 * '%-5s: %016x' % [ 'ID', self.object_id ] # => "ID : 00002b054ec93168"
2726 * 'foo = %{foo}' % {foo: 'bar'} # => "foo = bar"
2727 * 'foo = %{foo}, baz = %{baz}' % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
2728 *
2729 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2730 */
2731
2732static VALUE
2733rb_str_format_m(VALUE str, VALUE arg)
2734{
2735 VALUE tmp = rb_check_array_type(arg);
2736
2737 if (!NIL_P(tmp)) {
2738 VALUE result = rb_str_format_ary(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str, tmp);
2739 RB_GC_GUARD(tmp);
2740 return result;
2741 }
2742 return rb_str_format(1, &arg, str);
2743}
2744
2745static inline void
2746rb_check_lockedtmp(VALUE str)
2747{
2748 if (FL_TEST(str, STR_TMPLOCK)) {
2749 rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked");
2750 }
2751}
2752
2753// If none of these flags are set, we know we have an modifiable string.
2754// If any is set, we need to do more detailed checks.
2755#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2756static inline void
2757str_modifiable(VALUE str)
2758{
2759 RUBY_ASSERT(ruby_thread_has_gvl_p());
2760
2761 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2762 if (CHILLED_STRING_P(str)) {
2763 CHILLED_STRING_MUTATED(str);
2764 }
2765 rb_check_lockedtmp(str);
2766 rb_check_frozen(str);
2767 }
2768}
2769
2770static inline int
2771str_dependent_p(VALUE str)
2772{
2773 if (STR_EMBED_P(str) || !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2774 return FALSE;
2775 }
2776 else {
2777 return TRUE;
2778 }
2779}
2780
2781// If none of these flags are set, we know we have an independent string.
2782// If any is set, we need to do more detailed checks.
2783#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2784static inline int
2785str_independent(VALUE str)
2786{
2787 RUBY_ASSERT(ruby_thread_has_gvl_p());
2788
2789 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2790 str_modifiable(str);
2791 return !str_dependent_p(str);
2792 }
2793 return TRUE;
2794}
2795
2796static void
2797str_make_independent_expand(VALUE str, rb_len_t len, rb_len_t expand, const int termlen)
2798{
2799 RUBY_ASSERT(ruby_thread_has_gvl_p());
2800
2801 char *ptr;
2802 char *oldptr;
2803 rb_len_t capa = len + expand;
2804
2805 if (len > capa) len = capa;
2806
2807 if (!STR_EMBED_P(str) && str_embed_capa(str) >= capa + termlen) {
2808 ptr = RSTRING(str)->as.heap.ptr;
2809 STR_SET_EMBED(str);
2810 memcpy(RSTRING(str)->as.embed.ary, ptr, len);
2811 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
2812 STR_SET_LEN(str, len);
2813 return;
2814 }
2815
2816 ptr = ALLOC_N(char, (size_t)capa + termlen);
2817 oldptr = RSTRING_PTR(str);
2818 if (oldptr) {
2819 memcpy(ptr, oldptr, len);
2820 }
2821 if (FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2822 SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
2823 }
2824 STR_SET_NOEMBED(str);
2825 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2826 TERM_FILL(ptr + len, termlen);
2827 RSTRING(str)->as.heap.ptr = ptr;
2828 STR_SET_LEN(str, len);
2829 RSTRING(str)->as.heap.aux.capa = capa;
2830}
2831
2832void
2833rb_str_modify(VALUE str)
2834{
2835 if (!str_independent(str))
2836 str_make_independent(str);
2838}
2839
2840void
2842{
2843 RUBY_ASSERT(ruby_thread_has_gvl_p());
2844
2845 int termlen = TERM_LEN(str);
2846 rb_len_t len = RSTRING_LEN(str);
2847
2848 if (expand < 0) {
2849 rb_raise(rb_eArgError, "negative expanding string size");
2850 }
2851 if (expand >= RB_LEN_MAX - len) {
2852 rb_raise(rb_eArgError, "string size too big");
2853 }
2854
2855 if (!str_independent(str)) {
2856 str_make_independent_expand(str, len, expand, termlen);
2857 }
2858 else if (expand > 0) {
2859 RESIZE_CAPA_TERM(str, len + expand, termlen);
2860 }
2862}
2863
2864/* As rb_str_modify(), but don't clear coderange */
2865static void
2866str_modify_keep_cr(VALUE str)
2867{
2868 if (!str_independent(str))
2869 str_make_independent(str);
2871 /* Force re-scan later */
2873}
2874
2875static inline void
2876str_discard(VALUE str)
2877{
2878 str_modifiable(str);
2879 if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2880 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2881 RSTRING(str)->as.heap.ptr = 0;
2882 STR_SET_LEN(str, 0);
2883 }
2884}
2885
2886void
2888{
2889 int encindex = rb_enc_get_index(str);
2890
2891 if (RB_UNLIKELY(encindex == -1)) {
2892 rb_raise(rb_eTypeError, "not encoding capable object");
2893 }
2894
2895 if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
2896 return;
2897 }
2898
2899 rb_encoding *enc = rb_enc_from_index(encindex);
2900 if (!rb_enc_asciicompat(enc)) {
2901 rb_raise(rb_eEncCompatError, "ASCII incompatible encoding: %s", rb_enc_name(enc));
2902 }
2903}
2904
2905VALUE
2907{
2908 RUBY_ASSERT(ruby_thread_has_gvl_p());
2909
2910 VALUE s = *ptr;
2911 if (!RB_TYPE_P(s, T_STRING)) {
2912 s = rb_str_to_str(s);
2913 *ptr = s;
2914 }
2915 return s;
2916}
2917
2918char *
2920{
2921 VALUE str = rb_string_value(ptr);
2922 return RSTRING_PTR(str);
2923}
2924
2925static const char *
2926str_null_char(const char *s, rb_len_t len, const int minlen, rb_encoding *enc)
2927{
2928 const char *e = s + len;
2929
2930 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2931 if (zero_filled(s, minlen)) return s;
2932 }
2933 return 0;
2934}
2935
2936static char *
2937str_fill_term(VALUE str, char *s, rb_len_t len, int termlen)
2938{
2939 /* This function assumes that (capa + termlen) bytes of memory
2940 * is allocated, like many other functions in this file.
2941 */
2942 if (str_dependent_p(str)) {
2943 if (!zero_filled(s + len, termlen))
2944 str_make_independent_expand(str, len, 0L, termlen);
2945 }
2946 else {
2947 TERM_FILL(s + len, termlen);
2948 return s;
2949 }
2950 return RSTRING_PTR(str);
2951}
2952
2953void
2954rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen)
2955{
2956 rb_len_t capa = str_capacity(str, oldtermlen) + oldtermlen;
2957 rb_len_t len = RSTRING_LEN(str);
2958
2959 RUBY_ASSERT(capa >= len);
2960 if (capa - len < termlen) {
2961 rb_check_lockedtmp(str);
2962 str_make_independent_expand(str, len, 0L, termlen);
2963 }
2964 else if (str_dependent_p(str)) {
2965 if (termlen > oldtermlen)
2966 str_make_independent_expand(str, len, 0L, termlen);
2967 }
2968 else {
2969 if (!STR_EMBED_P(str)) {
2970 /* modify capa instead of realloc */
2971 RUBY_ASSERT(!FL_TEST((str), STR_SHARED));
2972 RSTRING(str)->as.heap.aux.capa = capa - termlen;
2973 }
2974 if (termlen > oldtermlen) {
2975 TERM_FILL(RSTRING_PTR(str) + len, termlen);
2976 }
2977 }
2978
2979 return;
2980}
2981
2982static char *
2983str_null_check(VALUE str, int *w)
2984{
2985 char *s = RSTRING_PTR(str);
2986 rb_len_t len = RSTRING_LEN(str);
2987 int minlen = 1;
2988
2989 if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
2990 rb_encoding *enc = rb_str_enc_get(str);
2991 minlen = rb_enc_mbminlen(enc);
2992
2993 if (minlen > 1) {
2994 *w = 1;
2995 if (str_null_char(s, len, minlen, enc)) {
2996 return NULL;
2997 }
2998 return str_fill_term(str, s, len, minlen);
2999 }
3000 }
3001
3002 *w = 0;
3003 if (!s || memchr(s, 0, len)) {
3004 return NULL;
3005 }
3006 if (s[len]) {
3007 s = str_fill_term(str, s, len, minlen);
3008 }
3009 return s;
3010}
3011
3012static char *str_to_cstr(VALUE str);
3013
3014const char *
3015rb_str_null_check(VALUE str)
3016{
3018
3019 const char *s;
3020 rb_len_t len;
3021 RSTRING_GETMEM(str, s, len);
3022
3023 if (RB_LIKELY(rb_str_enc_fastpath(str))) {
3024 if (!s || memchr(s, 0, len)) {
3025 rb_raise(rb_eArgError, "string contains null byte");
3026 }
3027 }
3028 else {
3029 str_to_cstr(str);
3030 }
3031
3032 return s;
3033}
3034
3035char *
3036rb_str_to_cstr(VALUE str)
3037{
3038 int w;
3039 return str_null_check(str, &w);
3040}
3041
3042char *
3044{
3045 VALUE str = rb_string_value(ptr);
3046 return str_to_cstr(str);
3047}
3048
3049static char *
3050str_to_cstr(VALUE str)
3051{
3052 int w;
3053 char *s = str_null_check(str, &w);
3054 if (!s) {
3055 if (w) {
3056 rb_raise(rb_eArgError, "string contains null char");
3057 }
3058 rb_raise(rb_eArgError, "string contains null byte");
3059 }
3060 return s;
3061}
3062
3063char *
3064rb_str_fill_terminator(VALUE str, const int newminlen)
3065{
3066 char *s = RSTRING_PTR(str);
3067 rb_len_t len = RSTRING_LEN(str);
3068 return str_fill_term(str, s, len, newminlen);
3069}
3070
3071VALUE
3073{
3074 str = rb_check_convert_type_with_id(str, T_STRING, "String", idTo_str);
3075 return str;
3076}
3077
3078/*
3079 * call-seq:
3080 * String.try_convert(object) -> object, new_string, or nil
3081 *
3082 * Attempts to convert the given +object+ to a string.
3083 *
3084 * If +object+ is already a string, returns +object+, unmodified.
3085 *
3086 * Otherwise if +object+ responds to <tt>:to_str</tt>,
3087 * calls <tt>object.to_str</tt> and returns the result.
3088 *
3089 * Returns +nil+ if +object+ does not respond to <tt>:to_str</tt>.
3090 *
3091 * Raises an exception unless <tt>object.to_str</tt> returns a string.
3092 */
3093static VALUE
3094rb_str_s_try_convert(VALUE dummy, VALUE str)
3095{
3096 return rb_check_string_type(str);
3097}
3098
3099static char*
3100str_nth_len(const char *p, const char *e, rb_len_t *nthp, rb_encoding *enc)
3101{
3102 rb_len_t nth = *nthp;
3103 if (rb_enc_mbmaxlen(enc) == 1) {
3104 p += nth;
3105 }
3106 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
3107 p += nth * rb_enc_mbmaxlen(enc);
3108 }
3109 else if (rb_enc_asciicompat(enc)) {
3110 const char *p2, *e2;
3111 int n;
3112
3113 while (p < e && 0 < nth) {
3114 e2 = p + nth;
3115 if (e < e2) {
3116 *nthp = nth;
3117 return (char *)e;
3118 }
3119 p2 = search_nonascii(p, e2);
3120 if (!p2) {
3121 nth -= e2 - p;
3122 *nthp = nth;
3123 return (char *)e2;
3124 }
3125 nth -= p2 - p;
3126 p = p2;
3127 n = rb_enc_mbclen(p, e, enc);
3128 p += n;
3129 nth--;
3130 }
3131 *nthp = nth;
3132 if (nth != 0) {
3133 return (char *)e;
3134 }
3135 return (char *)p;
3136 }
3137 else {
3138 while (p < e && nth--) {
3139 p += rb_enc_mbclen(p, e, enc);
3140 }
3141 }
3142 if (p > e) p = e;
3143 *nthp = nth;
3144 return (char*)p;
3145}
3146
3147char*
3148rb_enc_nth(const char *p, const char *e, rb_len_t nth, rb_encoding *enc)
3149{
3150 return str_nth_len(p, e, &nth, enc);
3151}
3152
3153static char*
3154str_nth(const char *p, const char *e, rb_len_t nth, rb_encoding *enc, int singlebyte)
3155{
3156 if (singlebyte)
3157 p += nth;
3158 else {
3159 p = str_nth_len(p, e, &nth, enc);
3160 }
3161 if (!p) return 0;
3162 if (p > e) p = e;
3163 return (char *)p;
3164}
3165
3166/* char offset to byte offset */
3167static rb_len_t
3168str_offset(const char *p, const char *e, rb_len_t nth, rb_encoding *enc, int singlebyte)
3169{
3170 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3171 if (!pp) return e - p;
3172 return pp - p;
3173}
3174
3177{
3178 return str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
3179 STR_ENC_GET(str), single_byte_optimizable(str));
3180}
3181
3182#ifdef NONASCII_MASK
3183static char *
3184str_utf8_nth(const char *p, const char *e, rb_len_t *nthp)
3185{
3186 rb_len_t nth = *nthp;
3187 if ((int)SIZEOF_VOIDP * 2 < e - p && (int)SIZEOF_VOIDP * 2 < nth) {
3188 const uintptr_t *s, *t;
3189 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3190 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3191 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
3192 while (p < (const char *)s) {
3193 if (is_utf8_lead_byte(*p)) nth--;
3194 p++;
3195 }
3196 do {
3197 nth -= count_utf8_lead_bytes_with_word(s);
3198 s++;
3199 } while (s < t && (int)SIZEOF_VOIDP <= nth);
3200 p = (char *)s;
3201 }
3202 while (p < e) {
3203 if (is_utf8_lead_byte(*p)) {
3204 if (nth == 0) break;
3205 nth--;
3206 }
3207 p++;
3208 }
3209 *nthp = nth;
3210 return (char *)p;
3211}
3212
3213static rb_len_t
3214str_utf8_offset(const char *p, const char *e, rb_len_t nth)
3215{
3216 const char *pp = str_utf8_nth(p, e, &nth);
3217 return pp - p;
3218}
3219#endif
3220
3221/* byte offset to char offset */
3224{
3225 if (single_byte_optimizable(str) || pos < 0)
3226 return pos;
3227 else {
3228 const char *p = RSTRING_PTR(str);
3229 return enc_strlen(p, p + pos, STR_ENC_GET(str), ENC_CODERANGE(str));
3230 }
3231}
3232
3233static VALUE
3234str_subseq(VALUE str, rb_len_t beg, rb_len_t len)
3235{
3236 VALUE str2;
3237
3238 RUBY_ASSERT(beg >= 0);
3239 RUBY_ASSERT(len >= 0);
3240 RUBY_ASSERT(beg+len <= RSTRING_LEN(str));
3241
3242 const int termlen = TERM_LEN(str);
3243 if (!SHARABLE_SUBSTRING_P(str, beg, len)) {
3244 str2 = rb_enc_str_new(RSTRING_PTR(str) + beg, len, rb_str_enc_get(str));
3245 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
3247 }
3248 RB_GC_GUARD(str);
3249 return str2;
3250 }
3251
3252 /* Sharing allocates a shared root as well unless str can be one itself, so
3253 * a copy is worth a larger slot only when it saves that second object. */
3254 const bool root_available = STR_SHARED_P(str) ||
3255 RB_FL_TEST_RAW(str, FL_FREEZE | STR_CHILLED) == FL_FREEZE;
3256 const size_t max_embed_size = root_available ?
3257 rb_gc_size_slot_size(sizeof(struct RString)) : STR_COPY_MAX_EMBED_SIZE;
3258 const size_t embed_size = rb_str_embed_size(len, termlen);
3259
3260 if (embed_size <= max_embed_size && rb_gc_size_allocatable_p(embed_size)) {
3261 str2 = str_alloc_embed(rb_cString, len + termlen);
3262 char *ptr2 = RSTRING(str2)->as.embed.ary;
3263 memcpy(ptr2, RSTRING_PTR(str) + beg, len);
3264 TERM_FILL(ptr2 + len, termlen);
3265
3266 STR_SET_LEN(str2, len);
3267 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
3269 }
3270
3271 RB_GC_GUARD(str);
3272 }
3273 else {
3274 str2 = str_alloc_heap(rb_cString);
3275 str_replace_shared(str2, str);
3276 RUBY_ASSERT(!STR_EMBED_P(str2));
3277 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
3278 ENC_CODERANGE_CLEAR(str2);
3279 }
3280
3281 RSTRING(str2)->as.heap.ptr += beg;
3282 if (RSTRING_LEN(str2) > len) {
3283 STR_SET_LEN(str2, len);
3284 }
3285 }
3286
3287 return str2;
3288}
3289
3290VALUE
3292{
3293 VALUE str2 = str_subseq(str, beg, len);
3294 rb_enc_cr_str_copy_for_substr(str2, str);
3295 return str2;
3296}
3297
3298char *
3300{
3301 rb_len_t len = *lenp;
3302 rb_len_t slen = -1L;
3303 const rb_len_t blen = RSTRING_LEN(str);
3304 rb_encoding *enc = STR_ENC_GET(str);
3305 const char *p, *s = RSTRING_PTR(str), *e = s + blen;
3306
3307 if (len < 0) return 0;
3308 if (beg == RB_LEN_MIN) return 0;
3309 if (!blen) {
3310 len = 0;
3311 }
3312 if (single_byte_optimizable(str)) {
3313 if (beg > blen) return 0;
3314 if (beg < 0) {
3315 beg += blen;
3316 if (beg < 0) return 0;
3317 }
3318 if (len > blen - beg)
3319 len = blen - beg;
3320 if (len < 0) return 0;
3321 p = s + beg;
3322 goto end;
3323 }
3324 if (beg < 0) {
3325 if (len > -beg) len = -beg;
3326 if ((ENC_CODERANGE(str) == ENC_CODERANGE_VALID) &&
3327 (-beg * rb_enc_mbmaxlen(enc) < blen / 8)) {
3328 beg = -beg;
3329 while (beg-- > len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3330 p = e;
3331 if (!p) return 0;
3332 while (len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3333 if (!p) return 0;
3334 len = e - p;
3335 goto end;
3336 }
3337 else {
3338 slen = str_strlen(str, enc);
3339 beg += slen;
3340 if (beg < 0) return 0;
3341 p = s + beg;
3342 if (len == 0) goto end;
3343 }
3344 }
3345 else if (beg > 0 && beg > blen) {
3346 return 0;
3347 }
3348 if (len == 0) {
3349 if (beg > str_strlen(str, enc)) return 0; /* str's enc */
3350 p = s + beg;
3351 }
3352#ifdef NONASCII_MASK
3353 else if (ENC_CODERANGE(str) == ENC_CODERANGE_VALID &&
3354 enc == rb_utf8_encoding()) {
3355 p = str_utf8_nth(s, e, &beg);
3356 if (beg > 0) return 0;
3357 len = str_utf8_offset(p, e, len);
3358 }
3359#endif
3360 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
3361 int char_sz = rb_enc_mbmaxlen(enc);
3362
3363 p = s + beg * char_sz;
3364 if (p > e) {
3365 return 0;
3366 }
3367 else if (len * char_sz > e - p)
3368 len = e - p;
3369 else
3370 len *= char_sz;
3371 }
3372 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3373 if (beg > 0) return 0;
3374 len = 0;
3375 }
3376 else {
3377 len = str_offset(p, e, len, enc, 0);
3378 }
3379 end:
3380 *lenp = len;
3381 RB_GC_GUARD(str);
3382 return (char *)p;
3383}
3384
3385static VALUE str_substr(VALUE str, rb_len_t beg, rb_len_t len, int empty);
3386
3387VALUE
3389{
3390 return str_substr(str, beg, len, TRUE);
3391}
3392
3393VALUE
3394rb_str_substr_two_fixnums(VALUE str, VALUE beg, VALUE len, int empty)
3395{
3396 return str_substr(str, NUM2LEN(beg), NUM2LEN(len), empty);
3397}
3398
3399static VALUE
3400str_substr(VALUE str, rb_len_t beg, rb_len_t len, int empty)
3401{
3402 const char *p = rb_str_subpos(str, beg, &len);
3403
3404 if (!p) return Qnil;
3405 if (!len && !empty) return Qnil;
3406
3407 beg = p - RSTRING_PTR(str);
3408
3409 VALUE str2 = str_subseq(str, beg, len);
3410 rb_enc_cr_str_copy_for_substr(str2, str);
3411 return str2;
3412}
3413
3414/* :nodoc: */
3415VALUE
3417{
3418 if (CHILLED_STRING_P(str)) {
3419 FL_UNSET_RAW(str, STR_CHILLED);
3420 }
3421
3422 if (OBJ_FROZEN(str)) return str;
3423 rb_str_resize(str, RSTRING_LEN(str));
3424 return rb_obj_freeze(str);
3425}
3426
3427/*
3428 * call-seq:
3429 * +string -> new_string or self
3430 *
3431 * Returns +self+ if +self+ is not frozen and can be mutated
3432 * without warning issuance.
3433 *
3434 * Otherwise returns <tt>self.dup</tt>, which is not frozen.
3435 *
3436 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
3437 */
3438static VALUE
3439str_uplus(VALUE str)
3440{
3441 if (OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3442 return rb_str_dup(str);
3443 }
3444 else {
3445 return str;
3446 }
3447}
3448
3449/*
3450 * call-seq:
3451 * -self -> frozen_string
3452 *
3453 * Returns a frozen string equal to +self+.
3454 *
3455 * The returned string is +self+ if and only if all of the following are true:
3456 *
3457 * - +self+ is already frozen.
3458 * - +self+ is an instance of \String (rather than of a subclass of \String)
3459 * - +self+ has no instance variables set on it.
3460 *
3461 * Otherwise, the returned string is a frozen copy of +self+.
3462 *
3463 * Returning +self+, when possible, saves duplicating +self+;
3464 * see {Data deduplication}[https://en.wikipedia.org/wiki/Data_deduplication].
3465 *
3466 * It may also save duplicating other, already-existing, strings:
3467 *
3468 * s0 = 'foo'
3469 * s1 = 'foo'
3470 * s0.object_id == s1.object_id # => false
3471 * (-s0).object_id == (-s1).object_id # => true
3472 *
3473 * Note that method #-@ is convenient for defining a constant:
3474 *
3475 * FileName = -'config/database.yml'
3476 *
3477 * While its alias #dedup is better suited for chaining:
3478 *
3479 * 'foo'.dedup.gsub!('o')
3480 *
3481 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
3482 */
3483static VALUE
3484str_uminus(VALUE str)
3485{
3486 if (!BARE_STRING_P(str) && !rb_obj_frozen_p(str)) {
3487 str = rb_str_dup(str);
3488 }
3489 return rb_fstring(str);
3490}
3491
3492RUBY_ALIAS_FUNCTION(rb_str_dup_frozen(VALUE str), rb_str_new_frozen, (str))
3493#define rb_str_dup_frozen rb_str_new_frozen
3494
3495VALUE
3497{
3498 rb_check_frozen(str);
3499 if (FL_TEST(str, STR_TMPLOCK)) {
3500 rb_raise(rb_eRuntimeError, "temporal locking already locked string");
3501 }
3502 FL_SET(str, STR_TMPLOCK);
3503 return str;
3504}
3505
3506VALUE
3508{
3509 rb_check_frozen(str);
3510 if (!FL_TEST(str, STR_TMPLOCK)) {
3511 rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string");
3512 }
3513 FL_UNSET(str, STR_TMPLOCK);
3514 return str;
3515}
3516
3517VALUE
3518rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg)
3519{
3520 rb_str_locktmp(str);
3521 return rb_ensure(func, arg, rb_str_unlocktmp, str);
3522}
3523
3524void
3526{
3527 RUBY_ASSERT(ruby_thread_has_gvl_p());
3528
3529 rb_len_t capa;
3530 const int termlen = TERM_LEN(str);
3531
3532 str_modifiable(str);
3533 if (STR_SHARED_P(str)) {
3534 rb_raise(rb_eRuntimeError, "can't set length of shared string");
3535 }
3536 if (len > (capa = (rb_len_t)str_capacity(str, termlen)) || len < 0) {
3537 rb_bug("probable buffer overflow: %"PRIdLEN" for %"PRIdLEN, len, capa);
3538 }
3539
3540 int cr = ENC_CODERANGE(str);
3541 if (len == 0) {
3542 /* Empty string does not contain non-ASCII */
3544 }
3545 else if (cr == ENC_CODERANGE_UNKNOWN) {
3546 /* Leave unknown. */
3547 }
3548 else if (len > RSTRING_LEN(str)) {
3549 if (ENC_CODERANGE_CLEAN_P(cr)) {
3550 /* Update the coderange regarding the extended part. */
3551 const char *const prev_end = RSTRING_END(str);
3552 const char *const new_end = RSTRING_PTR(str) + len;
3553 rb_encoding *enc = rb_enc_get(str);
3554 rb_str_coderange_scan_restartable(prev_end, new_end, enc, &cr);
3555 ENC_CODERANGE_SET(str, cr);
3556 }
3557 else if (cr == ENC_CODERANGE_BROKEN) {
3558 /* May be valid now, by appended part. */
3560 }
3561 }
3562 else if (len < RSTRING_LEN(str)) {
3563 if (cr != ENC_CODERANGE_7BIT) {
3564 /* ASCII-only string is keeping after truncated. Valid
3565 * and broken may be invalid or valid, leave unknown. */
3567 }
3568 }
3569
3570 STR_SET_LEN(str, len);
3571 TERM_FILL(&RSTRING_PTR(str)[len], termlen);
3572}
3573
3574VALUE
3575rb_str_resize(VALUE str, rb_len_t len)
3576{
3577 if (len < 0) {
3578 rb_raise(rb_eArgError, "negative string size (or size too big)");
3579 }
3580
3581 int independent = str_independent(str);
3582 rb_len_t slen = RSTRING_LEN(str);
3583 const int termlen = TERM_LEN(str);
3584
3585 if (slen > len || (termlen != 1 && slen < len)) {
3587 }
3588
3589 {
3590 rb_len_t capa;
3591 if (STR_EMBED_P(str)) {
3592 if (len == slen) return str;
3593 if (str_embed_capa(str) >= len + termlen) {
3594 STR_SET_LEN(str, len);
3595 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3596 return str;
3597 }
3598 str_make_independent_expand(str, slen, len - slen, termlen);
3599 }
3600 else if (str_embed_capa(str) >= len + termlen) {
3601 capa = RSTRING(str)->as.heap.aux.capa;
3602 char *ptr = STR_HEAP_PTR(str);
3603 STR_SET_EMBED(str);
3604 if (slen > len) slen = len;
3605 if (slen > 0) MEMCPY(RSTRING(str)->as.embed.ary, ptr, char, slen);
3606 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3607 STR_SET_LEN(str, len);
3608 if (independent) {
3609 SIZED_FREE_N(ptr, capa + termlen);
3610 }
3611 return str;
3612 }
3613 else if (!independent) {
3614 if (len == slen) return str;
3615 str_make_independent_expand(str, slen, len - slen, termlen);
3616 }
3617 else if ((capa = RSTRING(str)->as.heap.aux.capa) < len ||
3618 (capa - len) > (len < 1024 ? len : 1024)) {
3619 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
3620 (size_t)len + termlen, STR_HEAP_SIZE(str));
3621 RSTRING(str)->as.heap.aux.capa = len;
3622 }
3623 else if (len == slen) return str;
3624 STR_SET_LEN(str, len);
3625 TERM_FILL(RSTRING(str)->as.heap.ptr + len, termlen); /* sentinel */
3626 }
3627 return str;
3628}
3629
3630static void
3631str_ensure_available_capa(VALUE str, rb_len_t len)
3632{
3633 str_modify_keep_cr(str);
3634
3635 const int termlen = TERM_LEN(str);
3636 rb_len_t olen = RSTRING_LEN(str);
3637
3638 if (RB_UNLIKELY(olen > RB_LEN_MAX - len)) {
3639 rb_raise(rb_eArgError, "string sizes too big");
3640 }
3641
3642 rb_len_t total = olen + len;
3643 rb_len_t capa = str_capacity(str, termlen);
3644
3645 if (capa < total) {
3646 if (total >= RB_LEN_MAX / 2) {
3647 capa = total;
3648 }
3649 while (total > capa) {
3650 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3651 }
3652 RESIZE_CAPA_TERM(str, capa, termlen);
3653 }
3654}
3655
3656static VALUE
3657str_buf_cat4(VALUE str, const char *ptr, rb_len_t len, bool keep_cr)
3658{
3659 if (keep_cr) {
3660 str_modify_keep_cr(str);
3661 }
3662 else {
3663 rb_str_modify(str);
3664 }
3665 if (len == 0) return 0;
3666
3667 rb_len_t total, olen, off = -1;
3668 char *sptr;
3669 const int termlen = TERM_LEN(str);
3670
3671 RSTRING_GETMEM(str, sptr, olen);
3672 if (ptr >= sptr && ptr <= sptr + olen) {
3673 off = ptr - sptr;
3674 }
3675
3676 rb_len_t capa = str_capacity(str, termlen);
3677
3678 if (olen > RB_LEN_MAX - len) {
3679 rb_raise(rb_eArgError, "string sizes too big");
3680 }
3681 total = olen + len;
3682 if (capa < total) {
3683 if (total >= RB_LEN_MAX / 2) {
3684 capa = total;
3685 }
3686 while (total > capa) {
3687 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3688 }
3689 RESIZE_CAPA_TERM(str, capa, termlen);
3690 sptr = RSTRING_PTR(str);
3691 }
3692 if (off != -1) {
3693 ptr = sptr + off;
3694 }
3695 memcpy(sptr + olen, ptr, len);
3696 STR_SET_LEN(str, total);
3697 TERM_FILL(sptr + total, termlen); /* sentinel */
3698
3699 return str;
3700}
3701
3702#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3703#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3704
3705VALUE
3706rb_str_cat(VALUE str, const char *ptr, rb_len_t len)
3707{
3708 if (len == 0) return str;
3709 if (len < 0) {
3710 rb_raise(rb_eArgError, "negative string size (or size too big)");
3711 }
3712 return str_buf_cat(str, ptr, len);
3713}
3714
3715VALUE
3716rb_str_cat_cstr(VALUE str, const char *ptr)
3717{
3718 must_not_null(ptr);
3719 return rb_str_buf_cat(str, ptr, strlen(ptr));
3720}
3721
3722static void
3723rb_str_buf_cat_byte(VALUE str, unsigned char byte)
3724{
3725 RUBY_ASSERT(RB_ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT || RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII);
3726
3727 // We can't write directly to shared strings without impacting others, so we must make the string independent.
3728 if (UNLIKELY(!str_independent(str))) {
3729 str_make_independent(str);
3730 }
3731
3732 rb_len_t string_length = -1;
3733 const int null_terminator_length = 1;
3734 char *sptr;
3735 RSTRING_GETMEM(str, sptr, string_length);
3736
3737 // Ensure the resulting string wouldn't be too long.
3738 if (UNLIKELY(string_length > RB_LEN_MAX - 1)) {
3739 rb_raise(rb_eArgError, "string sizes too big");
3740 }
3741
3742 rb_len_t string_capacity = str_capacity(str, null_terminator_length);
3743
3744 // Get the code range before any modifications since those might clear the code range.
3745 int cr = ENC_CODERANGE(str);
3746
3747 // Check if the string has spare string_capacity to write the new byte.
3748 if (LIKELY(string_capacity >= string_length + 1)) {
3749 // In fast path we can write the new byte and note the string's new length.
3750 sptr[string_length] = byte;
3751 STR_SET_LEN(str, string_length + 1);
3752 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3753 }
3754 else {
3755 // If there's not enough string_capacity, make a call into the general string concatenation function.
3756 str_buf_cat(str, (char *)&byte, 1);
3757 }
3758
3759 // If the code range is already known, we can derive the resulting code range cheaply by looking at the byte we
3760 // just appended. If the code range is unknown, but the string was empty, then we can also derive the code range
3761 // by looking at the byte we just appended. Otherwise, we'd have to scan the bytes to determine the code range so
3762 // we leave it as unknown. It cannot be broken for binary strings so we don't need to handle that option.
3763 if (cr == ENC_CODERANGE_7BIT || string_length == 0) {
3764 if (ISASCII(byte)) {
3766 }
3767 else {
3769
3770 // Promote a US-ASCII string to ASCII-8BIT when a non-ASCII byte is appended.
3771 if (UNLIKELY(RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)) {
3772 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3773 }
3774 }
3775 }
3776}
3777
3778RUBY_ALIAS_FUNCTION(rb_str_buf_cat(VALUE str, const char *ptr, rb_len_t len), rb_str_cat, (str, ptr, len))
3779RUBY_ALIAS_FUNCTION(rb_str_buf_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3780RUBY_ALIAS_FUNCTION(rb_str_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3781
3782static VALUE
3783rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, rb_len_t len,
3784 int ptr_encindex, int ptr_cr, int *ptr_cr_ret)
3785{
3786 int str_encindex = ENCODING_GET(str);
3787 int res_encindex;
3788 int str_cr, res_cr;
3789 rb_encoding *str_enc, *ptr_enc;
3790
3791 str_cr = RSTRING_LEN(str) ? ENC_CODERANGE(str) : ENC_CODERANGE_7BIT;
3792
3793 if (str_encindex == ptr_encindex) {
3794 if (str_cr != ENC_CODERANGE_UNKNOWN && ptr_cr == ENC_CODERANGE_UNKNOWN) {
3795 ptr_cr = coderange_scan(ptr, len, rb_enc_from_index(ptr_encindex));
3796 }
3797 }
3798 else {
3799 str_enc = rb_enc_from_index(str_encindex);
3800 ptr_enc = rb_enc_from_index(ptr_encindex);
3801 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3802 if (len == 0)
3803 return str;
3804 if (RSTRING_LEN(str) == 0) {
3805 rb_str_buf_cat(str, ptr, len);
3806 ENCODING_CODERANGE_SET(str, ptr_encindex, ptr_cr);
3807 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3808 return str;
3809 }
3810 goto incompatible;
3811 }
3812 if (ptr_cr == ENC_CODERANGE_UNKNOWN) {
3813 ptr_cr = coderange_scan(ptr, len, ptr_enc);
3814 }
3815 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3816 if (ENCODING_IS_ASCII8BIT(str) || ptr_cr != ENC_CODERANGE_7BIT) {
3817 str_cr = rb_enc_str_coderange(str);
3818 }
3819 }
3820 }
3821 if (ptr_cr_ret)
3822 *ptr_cr_ret = ptr_cr;
3823
3824 if (str_encindex != ptr_encindex &&
3825 str_cr != ENC_CODERANGE_7BIT &&
3826 ptr_cr != ENC_CODERANGE_7BIT) {
3827 str_enc = rb_enc_from_index(str_encindex);
3828 ptr_enc = rb_enc_from_index(ptr_encindex);
3829 goto incompatible;
3830 }
3831
3832 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3833 res_encindex = str_encindex;
3834 res_cr = ENC_CODERANGE_UNKNOWN;
3835 }
3836 else if (str_cr == ENC_CODERANGE_7BIT) {
3837 if (ptr_cr == ENC_CODERANGE_7BIT) {
3838 res_encindex = str_encindex;
3839 res_cr = ENC_CODERANGE_7BIT;
3840 }
3841 else {
3842 res_encindex = ptr_encindex;
3843 res_cr = ptr_cr;
3844 }
3845 }
3846 else if (str_cr == ENC_CODERANGE_VALID) {
3847 res_encindex = str_encindex;
3848 if (ENC_CODERANGE_CLEAN_P(ptr_cr))
3849 res_cr = str_cr;
3850 else
3851 res_cr = ptr_cr;
3852 }
3853 else { /* str_cr == ENC_CODERANGE_BROKEN */
3854 res_encindex = str_encindex;
3855 res_cr = str_cr;
3856 if (0 < len) res_cr = ENC_CODERANGE_UNKNOWN;
3857 }
3858
3859 if (len < 0) {
3860 rb_raise(rb_eArgError, "negative string size (or size too big)");
3861 }
3862 str_buf_cat(str, ptr, len);
3863 ENCODING_CODERANGE_SET(str, res_encindex, res_cr);
3864 return str;
3865
3866 incompatible:
3867 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
3868 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3870}
3871
3872VALUE
3874{
3875 return rb_enc_cr_str_buf_cat(str, ptr, len,
3876 rb_enc_to_index(ptr_enc), ENC_CODERANGE_UNKNOWN, NULL);
3877}
3878
3879VALUE
3881{
3882 /* ptr must reference NUL terminated ASCII string. */
3883 int encindex = ENCODING_GET(str);
3884 rb_encoding *enc = rb_enc_from_index(encindex);
3885 if (rb_enc_asciicompat(enc)) {
3886 return rb_enc_cr_str_buf_cat(str, ptr, strlen(ptr),
3887 encindex, ENC_CODERANGE_7BIT, 0);
3888 }
3889 else {
3890 char *buf = ALLOCA_N(char, rb_enc_mbmaxlen(enc));
3891 while (*ptr) {
3892 unsigned int c = (unsigned char)*ptr;
3893 int len = rb_enc_codelen(c, enc);
3894 rb_enc_mbcput(c, buf, enc);
3895 rb_enc_cr_str_buf_cat(str, buf, len,
3896 encindex, ENC_CODERANGE_VALID, 0);
3897 ptr++;
3898 }
3899 return str;
3900 }
3901}
3902
3903VALUE
3905{
3906 int str2_cr = rb_enc_str_coderange(str2);
3907
3908 if (rb_str_enc_fastpath(str)) {
3909 switch (str2_cr) {
3910 case ENC_CODERANGE_7BIT:
3911 // If RHS is 7bit we can do simple concatenation
3912 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3913 RB_GC_GUARD(str2);
3914 return str;
3916 // If RHS is valid, we can do simple concatenation if encodings are the same
3917 if (ENCODING_GET_INLINED(str) == ENCODING_GET_INLINED(str2)) {
3918 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3919 int str_cr = ENC_CODERANGE(str);
3920 if (UNLIKELY(str_cr != ENC_CODERANGE_VALID)) {
3921 ENC_CODERANGE_SET(str, RB_ENC_CODERANGE_AND(str_cr, str2_cr));
3922 }
3923 RB_GC_GUARD(str2);
3924 return str;
3925 }
3926 }
3927 }
3928
3929 // NULL: str2's coderange is already cached
3930 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3931 ENCODING_GET(str2), str2_cr, NULL);
3932 RB_GC_GUARD(str2);
3933
3934 return str;
3935}
3936
3937VALUE
3939{
3940 StringValue(str2);
3941 return rb_str_buf_append(str, str2);
3942}
3943
3944VALUE
3945rb_str_concat_literals(size_t num, const VALUE *strary)
3946{
3947 VALUE str;
3948 size_t i, s = 0;
3949 rb_ulen_t len = 1;
3950
3951 if (UNLIKELY(!num)) return rb_str_new(0, 0);
3952 if (UNLIKELY(num == 1)) return rb_str_resurrect(strary[0]);
3953
3954 for (i = 0; i < num; ++i) { len += RSTRING_LEN(strary[i]); }
3955 str = rb_str_buf_new(len);
3956 str_enc_copy_direct(str, strary[0]);
3957
3958 for (i = s; i < num; ++i) {
3959 const VALUE v = strary[i];
3960 int encidx = ENCODING_GET(v);
3961
3962 rb_str_buf_append(str, v);
3963 if (encidx != ENCINDEX_US_ASCII) {
3964 if (ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)
3965 rb_enc_set_index(str, encidx);
3966 }
3967 }
3968 return str;
3969}
3970
3971/*
3972 * call-seq:
3973 * concat(*objects) -> string
3974 *
3975 * :include: doc/string/concat.rdoc
3976 */
3977static VALUE
3978rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
3979{
3980 str_modifiable(str);
3981
3982 if (argc == 1) {
3983 return rb_str_concat(str, argv[0]);
3984 }
3985 else if (argc > 1) {
3986 int i;
3987 VALUE arg_str = rb_str_tmp_new(0);
3988 rb_enc_copy(arg_str, str);
3989 for (i = 0; i < argc; i++) {
3990 rb_str_concat(arg_str, argv[i]);
3991 }
3992 rb_str_buf_append(str, arg_str);
3993 }
3994
3995 return str;
3996}
3997
3998/*
3999 * call-seq:
4000 * append_as_bytes(*objects) -> self
4001 *
4002 * Concatenates each object in +objects+ into +self+; returns +self+;
4003 * performs no encoding validation or conversion:
4004 *
4005 * s = 'foo'
4006 * s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82"
4007 * s.valid_encoding? # => false
4008 * s.append_as_bytes("\xAC 12")
4009 * s.valid_encoding? # => true
4010 *
4011 * When a given object is an integer,
4012 * the value is considered an 8-bit byte;
4013 * if the integer occupies more than one byte (i.e,. is greater than 255),
4014 * appends only the low-order byte (similar to String#setbyte):
4015 *
4016 * s = ""
4017 * s.append_as_bytes(0, 257) # => "\u0000\u0001"
4018 * s.bytesize # => 2
4019 *
4020 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4021 */
4022
4023VALUE
4024rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
4025{
4026 rb_len_t needed_capacity = 0;
4027 volatile VALUE t0;
4028 enum ruby_value_type *types = ALLOCV_N(enum ruby_value_type, t0, argc);
4029
4030 for (int index = 0; index < argc; index++) {
4031 VALUE obj = argv[index];
4032 enum ruby_value_type type = types[index] = rb_type(obj);
4033 switch (type) {
4034 case T_FIXNUM:
4035 case T_BIGNUM:
4036 needed_capacity++;
4037 break;
4038 case T_STRING:
4039 needed_capacity += RSTRING_LEN(obj);
4040 break;
4041 default:
4042 rb_raise(
4044 "wrong argument type %"PRIsVALUE" (expected String or Integer)",
4045 rb_obj_class(obj)
4046 );
4047 break;
4048 }
4049 }
4050
4051 str_ensure_available_capa(str, needed_capacity);
4052 char *sptr = RSTRING_END(str);
4053
4054 for (int index = 0; index < argc; index++) {
4055 VALUE obj = argv[index];
4056 enum ruby_value_type type = types[index];
4057 switch (type) {
4058 case T_FIXNUM:
4059 case T_BIGNUM: {
4060 argv[index] = obj = rb_int_and(obj, INT2FIX(0xff));
4061 char byte = (char)(NUM2INT(obj) & 0xFF);
4062 *sptr = byte;
4063 sptr++;
4064 break;
4065 }
4066 case T_STRING: {
4067 const char *ptr;
4068 rb_len_t len;
4069 RSTRING_GETMEM(obj, ptr, len);
4070 memcpy(sptr, ptr, len);
4071 sptr += len;
4072 break;
4073 }
4074 default:
4075 rb_bug("append_as_bytes arguments should have been validated");
4076 }
4077 }
4078
4079 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
4080 TERM_FILL(sptr, TERM_LEN(str)); /* sentinel */
4081
4082 int cr = ENC_CODERANGE(str);
4083 switch (cr) {
4084 case ENC_CODERANGE_7BIT: {
4085 for (int index = 0; index < argc; index++) {
4086 VALUE obj = argv[index];
4087 enum ruby_value_type type = types[index];
4088 switch (type) {
4089 case T_FIXNUM:
4090 case T_BIGNUM: {
4091 if (!ISASCII(NUM2INT(obj))) {
4092 goto clear_cr;
4093 }
4094 break;
4095 }
4096 case T_STRING: {
4097 if (ENC_CODERANGE(obj) != ENC_CODERANGE_7BIT) {
4098 goto clear_cr;
4099 }
4100 break;
4101 }
4102 default:
4103 rb_bug("append_as_bytes arguments should have been validated");
4104 }
4105 }
4106 break;
4107 }
4109 if (ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT) {
4110 goto keep_cr;
4111 }
4112 else {
4113 goto clear_cr;
4114 }
4115 break;
4116 default:
4117 goto clear_cr;
4118 break;
4119 }
4120
4121 clear_cr:
4122 // If no fast path was hit, we clear the coderange.
4123 // append_as_bytes is predominantly meant to be used in
4124 // buffering situation, hence it's likely the coderange
4125 // will never be scanned, so it's not worth spending time
4126 // precomputing the coderange except for simple and common
4127 // situations.
4129 keep_cr:
4130 ALLOCV_END(t0);
4131 return str;
4132}
4133
4134/*
4135 * call-seq:
4136 * self << object -> self
4137 *
4138 * Appends a string representation of +object+ to +self+;
4139 * returns +self+.
4140 *
4141 * If +object+ is a string, appends it to +self+:
4142 *
4143 * s = 'foo'
4144 * s << 'bar' # => "foobar"
4145 * s # => "foobar"
4146 *
4147 * If +object+ is an integer,
4148 * its value is considered a codepoint;
4149 * converts the value to a character before concatenating:
4150 *
4151 * s = 'foo'
4152 * s << 33 # => "foo!"
4153 *
4154 * Additionally, if the codepoint is in range <tt>0..0xff</tt>
4155 * and the encoding of +self+ is Encoding::US_ASCII,
4156 * changes the encoding to Encoding::ASCII_8BIT:
4157 *
4158 * s = 'foo'.encode(Encoding::US_ASCII)
4159 * s.encoding # => #<Encoding:US-ASCII>
4160 * s << 0xff # => "foo\xFF"
4161 * s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
4162 *
4163 * Raises RangeError if that codepoint is not representable in the encoding of +self+:
4164 *
4165 * s = 'foo'
4166 * s.encoding # => #<Encoding:UTF-8>
4167 * s << 0x00110000 # 1114112 out of char range (RangeError)
4168 * s = 'foo'.encode(Encoding::EUC_JP)
4169 * s << 0x00800080 # invalid codepoint 0x800080 in EUC-JP (RangeError)
4170 *
4171 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4172 */
4173VALUE
4175{
4176 unsigned int code;
4177 rb_encoding *enc = STR_ENC_GET(str1);
4178 int encidx;
4179
4180 if (RB_INTEGER_TYPE_P(str2)) {
4181 if (rb_num_to_uint(str2, &code) == 0) {
4182 }
4183 else if (FIXNUM_P(str2)) {
4184 rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(str2));
4185 }
4186 else {
4187 rb_raise(rb_eRangeError, "bignum out of char range");
4188 }
4189 }
4190 else {
4191 return rb_str_append(str1, str2);
4192 }
4193
4194 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4195
4196 if (encidx >= 0) {
4197 rb_str_buf_cat_byte(str1, (unsigned char)code);
4198 }
4199 else {
4200 rb_len_t pos = RSTRING_LEN(str1);
4201 int cr = ENC_CODERANGE(str1);
4202 int len;
4203 char *buf;
4204
4205 switch (len = rb_enc_codelen(code, enc)) {
4206 case ONIGERR_INVALID_CODE_POINT_VALUE:
4207 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4208 break;
4209 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4210 case 0:
4211 rb_raise(rb_eRangeError, "%u out of char range", code);
4212 break;
4213 }
4214 buf = ALLOCA_N(char, len + 1);
4215 rb_enc_mbcput(code, buf, enc);
4216 if (rb_enc_precise_mbclen(buf, buf + len + 1, enc) != len) {
4217 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4218 }
4219 rb_str_resize(str1, pos+len);
4220 memcpy(RSTRING_PTR(str1) + pos, buf, len);
4221 if (cr == ENC_CODERANGE_7BIT && code > 127) {
4223 }
4224 else if (cr == ENC_CODERANGE_BROKEN) {
4226 }
4227 ENC_CODERANGE_SET(str1, cr);
4228 }
4229 return str1;
4230}
4231
4232int
4233rb_ascii8bit_appendable_encoding_index(rb_encoding *enc, unsigned int code)
4234{
4235 int encidx = rb_enc_to_index(enc);
4236
4237 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4238 /* US-ASCII automatically extended to ASCII-8BIT */
4239 if (code > 0xFF) {
4240 rb_raise(rb_eRangeError, "%u out of char range", code);
4241 }
4242 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4243 return ENCINDEX_ASCII_8BIT;
4244 }
4245 return encidx;
4246 }
4247 else {
4248 return -1;
4249 }
4250}
4251
4252/*
4253 * call-seq:
4254 * prepend(*other_strings) -> new_string
4255 *
4256 * Prefixes to +self+ the concatenation of the given +other_strings+; returns +self+:
4257 *
4258 * 'baz'.prepend('foo', 'bar') # => "foobarbaz"
4259 *
4260 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4261 *
4262 */
4263
4264static VALUE
4265rb_str_prepend_multi(int argc, VALUE *argv, VALUE str)
4266{
4267 str_modifiable(str);
4268
4269 if (argc == 1) {
4270 rb_str_update(str, 0L, 0L, argv[0]);
4271 }
4272 else if (argc > 1) {
4273 int i;
4274 VALUE arg_str = rb_str_tmp_new(0);
4275 rb_enc_copy(arg_str, str);
4276 for (i = 0; i < argc; i++) {
4277 rb_str_append(arg_str, argv[i]);
4278 }
4279 rb_str_update(str, 0L, 0L, arg_str);
4280 }
4281
4282 return str;
4283}
4284
4285st_index_t
4287{
4288 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) {
4289 st_index_t precomputed_hash;
4290 memcpy(&precomputed_hash, RSTRING_END(str) + TERM_LEN(str), sizeof(precomputed_hash));
4291
4292 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4293 return precomputed_hash;
4294 }
4295
4296 return str_do_hash(str);
4297}
4298
4299int
4301{
4302 rb_len_t len1, len2;
4303 const char *ptr1, *ptr2;
4304 RSTRING_GETMEM(str1, ptr1, len1);
4305 RSTRING_GETMEM(str2, ptr2, len2);
4306 return (len1 != len2 ||
4307 !rb_str_comparable(str1, str2) ||
4308 memcmp(ptr1, ptr2, len1) != 0);
4309}
4310
4311/*
4312 * call-seq:
4313 * hash -> integer
4314 *
4315 * :include: doc/string/hash.rdoc
4316 *
4317 */
4318
4319static VALUE
4320rb_str_hash_m(VALUE str)
4321{
4322 st_index_t hval = rb_str_hash(str);
4323 return ST2FIX(hval);
4324}
4325
4326#define lesser(a,b) (((a)>(b))?(b):(a))
4327
4328int
4330{
4331 int idx1, idx2;
4332 int rc1, rc2;
4333
4334 if (RSTRING_LEN(str1) == 0) return TRUE;
4335 if (RSTRING_LEN(str2) == 0) return TRUE;
4336 idx1 = ENCODING_GET(str1);
4337 idx2 = ENCODING_GET(str2);
4338 if (idx1 == idx2) return TRUE;
4339 rc1 = rb_enc_str_coderange(str1);
4340 rc2 = rb_enc_str_coderange(str2);
4341 if (rc1 == ENC_CODERANGE_7BIT) {
4342 if (rc2 == ENC_CODERANGE_7BIT) return TRUE;
4343 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4344 return TRUE;
4345 }
4346 if (rc2 == ENC_CODERANGE_7BIT) {
4347 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4348 return TRUE;
4349 }
4350 return FALSE;
4351}
4352
4353int
4355{
4356 rb_len_t len1, len2;
4357 const char *ptr1, *ptr2;
4358 int retval;
4359
4360 if (str1 == str2) return 0;
4361 RSTRING_GETMEM(str1, ptr1, len1);
4362 RSTRING_GETMEM(str2, ptr2, len2);
4363 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4364 if (len1 == len2) {
4365 if (!rb_str_comparable(str1, str2)) {
4366 if (ENCODING_GET(str1) > ENCODING_GET(str2))
4367 return 1;
4368 return -1;
4369 }
4370 return 0;
4371 }
4372 if (len1 > len2) return 1;
4373 return -1;
4374 }
4375 if (retval > 0) return 1;
4376 return -1;
4377}
4378
4379/*
4380 * call-seq:
4381 * self == other -> true or false
4382 *
4383 * Returns whether +other+ is equal to +self+.
4384 *
4385 * When +other+ is a string, returns whether +other+ has the same length and content as +self+:
4386 *
4387 * s = 'foo'
4388 * s == 'foo' # => true
4389 * s == 'food' # => false
4390 * s == 'FOO' # => false
4391 *
4392 * Returns +false+ if the two strings' encodings are not compatible:
4393 *
4394 * "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false
4395 *
4396 * When +other+ is not a string:
4397 *
4398 * - If +other+ responds to method <tt>to_str</tt>,
4399 * <tt>other == self</tt> is called and its return value is returned.
4400 * - If +other+ does not respond to <tt>to_str</tt>,
4401 * +false+ is returned.
4402 *
4403 * Related: {Comparing}[rdoc-ref:String@Comparing].
4404 */
4405
4406VALUE
4408{
4409 if (str1 == str2) return Qtrue;
4410 if (!RB_TYPE_P(str2, T_STRING)) {
4411 if (!rb_respond_to(str2, idTo_str)) {
4412 return Qfalse;
4413 }
4414 return rb_equal(str2, str1);
4415 }
4416 return rb_str_eql_internal(str1, str2);
4417}
4418
4419/*
4420 * call-seq:
4421 * eql?(object) -> true or false
4422 *
4423 * :include: doc/string/eql_p.rdoc
4424 *
4425 */
4426
4427VALUE
4428rb_str_eql(VALUE str1, VALUE str2)
4429{
4430 if (str1 == str2) return Qtrue;
4431 if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
4432 return rb_str_eql_internal(str1, str2);
4433}
4434
4435/*
4436 * call-seq:
4437 * self <=> other -> -1, 0, 1, or nil
4438 *
4439 * Compares +self+ and +other+,
4440 * evaluating their _contents_, not their _lengths_.
4441 *
4442 * Returns:
4443 *
4444 * - +-1+, if +self+ is smaller.
4445 * - +0+, if the two are equal.
4446 * - +1+, if +self+ is larger.
4447 * - +nil+, if the two are incomparable.
4448 *
4449 * Examples:
4450 *
4451 * 'a' <=> 'b' # => -1
4452 * 'a' <=> 'ab' # => -1
4453 * 'a' <=> 'a' # => 0
4454 * 'b' <=> 'a' # => 1
4455 * 'ab' <=> 'a' # => 1
4456 * 'a' <=> :a # => nil
4457 *
4458 * \Class \String includes module Comparable,
4459 * each of whose methods uses String#<=> for comparison.
4460 *
4461 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4462 */
4463
4464static VALUE
4465rb_str_cmp_m(VALUE str1, VALUE str2)
4466{
4467 int result;
4468 VALUE s = rb_check_string_type(str2);
4469 if (NIL_P(s)) {
4470 return rb_invcmp(str1, str2);
4471 }
4472 result = rb_str_cmp(str1, s);
4473 return INT2FIX(result);
4474}
4475
4476static VALUE str_casecmp(VALUE str1, VALUE str2);
4477static VALUE str_casecmp_p(VALUE str1, VALUE str2);
4478
4479/*
4480 * call-seq:
4481 * casecmp(other_string) -> -1, 0, 1, or nil
4482 *
4483 * Ignoring case, compares +self+ and +other_string+; returns:
4484 *
4485 * - -1 if <tt>self.downcase</tt> is smaller than <tt>other_string.downcase</tt>.
4486 * - 0 if the two are equal.
4487 * - 1 if <tt>self.downcase</tt> is larger than <tt>other_string.downcase</tt>.
4488 * - +nil+ if the two are incomparable.
4489 *
4490 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4491 *
4492 * Examples:
4493 *
4494 * 'foo'.casecmp('goo') # => -1
4495 * 'goo'.casecmp('foo') # => 1
4496 * 'foo'.casecmp('food') # => -1
4497 * 'food'.casecmp('foo') # => 1
4498 * 'FOO'.casecmp('foo') # => 0
4499 * 'foo'.casecmp('FOO') # => 0
4500 * 'foo'.casecmp(1) # => nil
4501 *
4502 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4503 */
4504
4505VALUE
4506rb_str_casecmp(VALUE str1, VALUE str2)
4507{
4508 VALUE s = rb_check_string_type(str2);
4509 if (NIL_P(s)) {
4510 return Qnil;
4511 }
4512 return str_casecmp(str1, s);
4513}
4514
4515static VALUE
4516str_casecmp(VALUE str1, VALUE str2)
4517{
4518 rb_len_t len;
4519 rb_encoding *enc;
4520 const char *p1, *p1end, *p2, *p2end;
4521
4522 enc = rb_enc_compatible(str1, str2);
4523 if (!enc) {
4524 return Qnil;
4525 }
4526
4527 p1 = RSTRING_PTR(str1); p1end = RSTRING_END(str1);
4528 p2 = RSTRING_PTR(str2); p2end = RSTRING_END(str2);
4529 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4530 while (p1 < p1end && p2 < p2end) {
4531 if (*p1 != *p2) {
4532 unsigned int c1 = TOLOWER(*p1 & 0xff);
4533 unsigned int c2 = TOLOWER(*p2 & 0xff);
4534 if (c1 != c2)
4535 return INT2FIX(c1 < c2 ? -1 : 1);
4536 }
4537 p1++;
4538 p2++;
4539 }
4540 }
4541 else {
4542 while (p1 < p1end && p2 < p2end) {
4543 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4544 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4545
4546 if (0 <= c1 && 0 <= c2) {
4547 c1 = TOLOWER(c1);
4548 c2 = TOLOWER(c2);
4549 if (c1 != c2)
4550 return INT2FIX(c1 < c2 ? -1 : 1);
4551 }
4552 else {
4553 int r;
4554 l1 = rb_enc_mbclen(p1, p1end, enc);
4555 l2 = rb_enc_mbclen(p2, p2end, enc);
4556 len = l1 < l2 ? l1 : l2;
4557 r = memcmp(p1, p2, len);
4558 if (r != 0)
4559 return INT2FIX(r < 0 ? -1 : 1);
4560 if (l1 != l2)
4561 return INT2FIX(l1 < l2 ? -1 : 1);
4562 }
4563 p1 += l1;
4564 p2 += l2;
4565 }
4566 }
4567 if (p1 == p1end && p2 == p2end) return INT2FIX(0);
4568 if (p1 == p1end) return INT2FIX(-1);
4569 return INT2FIX(1);
4570}
4571
4572/*
4573 * call-seq:
4574 * casecmp?(other_string) -> true, false, or nil
4575 *
4576 * Returns +true+ if +self+ and +other_string+ are equal after
4577 * Unicode case folding, +false+ if unequal, +nil+ if incomparable.
4578 *
4579 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4580 *
4581 * Examples:
4582 *
4583 * 'foo'.casecmp?('goo') # => false
4584 * 'goo'.casecmp?('foo') # => false
4585 * 'foo'.casecmp?('food') # => false
4586 * 'food'.casecmp?('foo') # => false
4587 * 'FOO'.casecmp?('foo') # => true
4588 * 'foo'.casecmp?('FOO') # => true
4589 * 'foo'.casecmp?(1) # => nil
4590 *
4591 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4592 */
4593
4594static VALUE
4595rb_str_casecmp_p(VALUE str1, VALUE str2)
4596{
4597 VALUE s = rb_check_string_type(str2);
4598 if (NIL_P(s)) {
4599 return Qnil;
4600 }
4601 return str_casecmp_p(str1, s);
4602}
4603
4604static VALUE
4605str_casecmp_p(VALUE str1, VALUE str2)
4606{
4607 rb_encoding *enc;
4608 VALUE folded_str1, folded_str2;
4609 VALUE fold_opt = sym_fold;
4610
4611 enc = rb_enc_compatible(str1, str2);
4612 if (!enc) {
4613 return Qnil;
4614 }
4615
4616 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4617 if (RSTRING_LEN(str1) != RSTRING_LEN(str2)) return Qfalse;
4618 const char *p1 = RSTRING_PTR(str1), *p1end = RSTRING_END(str1);
4619 const char *p2 = RSTRING_PTR(str2);
4620 while (p1 < p1end) {
4621 if (*p1 != *p2 && TOLOWER((unsigned char)*p1) != TOLOWER((unsigned char)*p2)) {
4622 return Qfalse;
4623 }
4624 p1++;
4625 p2++;
4626 }
4627 return Qtrue;
4628 }
4629
4630 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4631 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4632
4633 return rb_str_eql(folded_str1, folded_str2);
4634}
4635
4636static rb_len_t
4637strseq_core(const char *str_ptr, const char *str_ptr_end, rb_len_t str_len,
4638 const char *sub_ptr, rb_len_t sub_len, rb_len_t offset, rb_encoding *enc)
4639{
4640 const char *search_start = str_ptr;
4641 rb_len_t pos, search_len = str_len - offset;
4642
4643 for (;;) {
4644 const char *t;
4645 pos = rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4646 if (pos < 0) return pos;
4647 t = rb_enc_right_char_head(search_start, search_start+pos, str_ptr_end, enc);
4648 if (t == search_start + pos) break;
4649 search_len -= t - search_start;
4650 if (search_len <= 0) return -1;
4651 offset += t - search_start;
4652 search_start = t;
4653 }
4654 return pos + offset;
4655}
4656
4657/* found index in byte */
4658#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4659#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4660
4661static rb_len_t
4662rb_strseq_index(VALUE str, VALUE sub, rb_len_t offset, int in_byte)
4663{
4664 const char *str_ptr, *str_ptr_end, *sub_ptr;
4665 rb_len_t str_len, sub_len;
4666 rb_encoding *enc;
4667
4668 enc = rb_enc_check(str, sub);
4669 if (is_broken_string(sub)) return -1;
4670
4671 str_ptr = RSTRING_PTR(str);
4672 str_ptr_end = RSTRING_END(str);
4673 str_len = RSTRING_LEN(str);
4674 sub_ptr = RSTRING_PTR(sub);
4675 sub_len = RSTRING_LEN(sub);
4676
4677 if (str_len < sub_len) return -1;
4678
4679 if (offset != 0) {
4680 rb_len_t str_len_char, sub_len_char;
4681 int single_byte = single_byte_optimizable(str);
4682 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4683 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4684 if (offset < 0) {
4685 offset += str_len_char;
4686 if (offset < 0) return -1;
4687 }
4688 if (str_len_char - offset < sub_len_char) return -1;
4689 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4690 str_ptr += offset;
4691 }
4692 if (sub_len == 0) return offset;
4693
4694 /* need proceed one character at a time */
4695 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4696}
4697
4698
4699/*
4700 * call-seq:
4701 * index(pattern, offset = 0) -> integer or nil
4702 *
4703 * :include: doc/string/index.rdoc
4704 *
4705 */
4706
4707static VALUE
4708rb_str_index_m(int argc, VALUE *argv, VALUE str)
4709{
4710 VALUE sub;
4711 VALUE initpos;
4712 rb_encoding *enc = STR_ENC_GET(str);
4713 rb_len_t pos;
4714
4715 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4716 rb_len_t slen = str_strlen(str, enc); /* str's enc */
4717 pos = NUM2LEN(initpos);
4718 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4719 if (RB_TYPE_P(sub, T_REGEXP)) {
4721 }
4722 return Qnil;
4723 }
4724 }
4725 else {
4726 pos = 0;
4727 }
4728
4729 if (RB_TYPE_P(sub, T_REGEXP)) {
4730 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4731 enc, single_byte_optimizable(str));
4732
4733 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4734 VALUE match = rb_backref_get();
4735 pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
4736 return LEN2NUM(pos);
4737 }
4738 }
4739 else {
4740 StringValue(sub);
4741 pos = rb_str_index(str, sub, pos);
4742 if (pos >= 0) {
4743 pos = rb_str_sublen(str, pos);
4744 return LEN2NUM(pos);
4745 }
4746 }
4747 return Qnil;
4748}
4749
4750/* Ensure that the given pos is a valid character boundary.
4751 * Note that in this function, "character" means a code point
4752 * (Unicode scalar value), not a grapheme cluster.
4753 */
4754static void
4755str_ensure_byte_pos(VALUE str, rb_len_t pos)
4756{
4757 if (!single_byte_optimizable(str)) {
4758 const char *s = RSTRING_PTR(str);
4759 const char *e = RSTRING_END(str);
4760 const char *p = s + pos;
4761 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4762 rb_raise(rb_eIndexError,
4763 "offset %"PRIdLEN" does not land on character boundary", pos);
4764 }
4765 }
4766}
4767
4768/*
4769 * call-seq:
4770 * byteindex(object, offset = 0) -> integer or nil
4771 *
4772 * Returns the 0-based integer index of a substring of +self+
4773 * specified by +object+ (a string or Regexp) and +offset+,
4774 * or +nil+ if there is no such substring;
4775 * the returned index is the count of _bytes_ (not characters).
4776 *
4777 * When +object+ is a string,
4778 * returns the index of the first found substring equal to +object+:
4779 *
4780 * s = 'foo' # => "foo"
4781 * s.size # => 3 # Three 1-byte characters.
4782 * s.bytesize # => 3 # Three bytes.
4783 * s.byteindex('f') # => 0
4784 * s.byteindex('o') # => 1
4785 * s.byteindex('oo') # => 1
4786 * s.byteindex('ooo') # => nil
4787 *
4788 * When +object+ is a Regexp,
4789 * returns the index of the first found substring matching +object+;
4790 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
4791 *
4792 * s = 'foo'
4793 * s.byteindex(/f/) # => 0
4794 * $~ # => #<MatchData "f">
4795 * s.byteindex(/o/) # => 1
4796 * s.byteindex(/oo/) # => 1
4797 * s.byteindex(/ooo/) # => nil
4798 * $~ # => nil
4799 *
4800 * \Integer argument +offset+, if given, specifies the 0-based index
4801 * of the byte where searching is to begin.
4802 *
4803 * When +offset+ is non-negative,
4804 * searching begins at byte position +offset+:
4805 *
4806 * s = 'foo'
4807 * s.byteindex('o', 1) # => 1
4808 * s.byteindex('o', 2) # => 2
4809 * s.byteindex('o', 3) # => nil
4810 *
4811 * When +offset+ is negative, counts backward from the end of +self+:
4812 *
4813 * s = 'foo'
4814 * s.byteindex('o', -1) # => 2
4815 * s.byteindex('o', -2) # => 1
4816 * s.byteindex('o', -3) # => 1
4817 * s.byteindex('o', -4) # => nil
4818 *
4819 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
4820 *
4821 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
4822 * s.size # => 2 # Two 3-byte characters.
4823 * s.bytesize # => 6 # Six bytes.
4824 * s.byteindex("\uFFFF") # => 0
4825 * s.byteindex("\uFFFF", 1) # Raises IndexError
4826 * s.byteindex("\uFFFF", 2) # Raises IndexError
4827 * s.byteindex("\uFFFF", 3) # => 3
4828 * s.byteindex("\uFFFF", 4) # Raises IndexError
4829 * s.byteindex("\uFFFF", 5) # Raises IndexError
4830 * s.byteindex("\uFFFF", 6) # => nil
4831 *
4832 * Related: see {Querying}[rdoc-ref:String@Querying].
4833 */
4834
4835static VALUE
4836rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
4837{
4838 VALUE sub;
4839 VALUE initpos;
4840 rb_len_t pos;
4841
4842 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4843 pos = NUM2LEN(initpos);
4844 rb_len_t slen = RSTRING_LEN(str);
4845 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4846 if (RB_TYPE_P(sub, T_REGEXP)) {
4848 }
4849 return Qnil;
4850 }
4851 }
4852 else {
4853 pos = 0;
4854 }
4855
4856 str_ensure_byte_pos(str, pos);
4857
4858 if (RB_TYPE_P(sub, T_REGEXP)) {
4859 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4860 VALUE match = rb_backref_get();
4861 pos = RMATCH_BEG(match, 0);
4862 return LEN2NUM(pos);
4863 }
4864 }
4865 else {
4866 StringValue(sub);
4867 pos = rb_str_byteindex(str, sub, pos);
4868 if (pos >= 0) return LEN2NUM(pos);
4869 }
4870 return Qnil;
4871}
4872
4873static rb_len_t
4874str_rindex(VALUE str, VALUE sub, const char *s, rb_encoding *enc)
4875{
4876 const char *hit, *adjusted, *sbeg, *e, *t;
4877 int c;
4878 rb_len_t slen, searchlen;
4879
4880 sbeg = RSTRING_PTR(str);
4881 slen = RSTRING_LEN(sub);
4882 if (slen == 0) return s - sbeg;
4883 e = RSTRING_END(str);
4884 t = RSTRING_PTR(sub);
4885 c = *t & 0xff;
4886 searchlen = s - sbeg + 1;
4887
4888 if (s + slen <= e && memcmp(s, t, slen) == 0) {
4889 return s - sbeg;
4890 }
4891
4892 do {
4893 hit = memrchr(sbeg, c, searchlen);
4894 if (!hit) break;
4895 adjusted = rb_enc_left_char_head(sbeg, hit, e, enc);
4896 if (hit != adjusted) {
4897 searchlen = adjusted - sbeg;
4898 continue;
4899 }
4900 if (hit + slen <= e && memcmp(hit, t, slen) == 0)
4901 return hit - sbeg;
4902 searchlen = adjusted - sbeg;
4903 } while (searchlen > 0);
4904
4905 return -1;
4906}
4907
4908/* found index in byte */
4909static rb_len_t
4910rb_str_rindex(VALUE str, VALUE sub, rb_len_t pos)
4911{
4912 rb_len_t len, slen;
4913 const char *sbeg, *s;
4914 rb_encoding *enc;
4915 int singlebyte;
4916
4917 enc = rb_enc_check(str, sub);
4918 if (is_broken_string(sub)) return -1;
4919 singlebyte = single_byte_optimizable(str);
4920 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc); /* rb_enc_check */
4921 slen = str_strlen(sub, enc); /* rb_enc_check */
4922
4923 /* substring longer than string */
4924 if (len < slen) return -1;
4925 /* character counts, so the byte tail can still be shorter than sub */
4926 if (len - pos < slen) pos = len - slen;
4927 if (len == 0) return pos;
4928
4929 sbeg = RSTRING_PTR(str);
4930
4931 if (pos == 0) {
4932 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4933 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4934 return 0;
4935 }
4936 else {
4937 return -1;
4938 }
4939 }
4940
4941 s = str_nth(sbeg, RSTRING_END(str), pos, enc, singlebyte);
4942 return str_rindex(str, sub, s, enc);
4943}
4944
4945/*
4946 * call-seq:
4947 * rindex(pattern, offset = self.length) -> integer or nil
4948 *
4949 * :include:doc/string/rindex.rdoc
4950 *
4951 */
4952
4953static VALUE
4954rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
4955{
4956 VALUE sub;
4957 VALUE initpos;
4958 rb_encoding *enc = STR_ENC_GET(str);
4959 rb_len_t pos, len = str_strlen(str, enc); /* str's enc */
4960
4961 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4962 pos = NUM2LEN(initpos);
4963 if (pos < 0 && (pos += len) < 0) {
4964 if (RB_TYPE_P(sub, T_REGEXP)) {
4966 }
4967 return Qnil;
4968 }
4969 if (pos > len) pos = len;
4970 }
4971 else {
4972 pos = len;
4973 }
4974
4975 if (RB_TYPE_P(sub, T_REGEXP)) {
4976 /* enc = rb_enc_check(str, sub); */
4977 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4978 enc, single_byte_optimizable(str));
4979
4980 if (rb_reg_search(sub, str, pos, 1) >= 0) {
4981 VALUE match = rb_backref_get();
4982 pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
4983 return LEN2NUM(pos);
4984 }
4985 }
4986 else {
4987 StringValue(sub);
4988 pos = rb_str_rindex(str, sub, pos);
4989 if (pos >= 0) {
4990 pos = rb_str_sublen(str, pos);
4991 return LEN2NUM(pos);
4992 }
4993 }
4994 return Qnil;
4995}
4996
4997static rb_len_t
4998rb_str_byterindex(VALUE str, VALUE sub, rb_len_t pos)
4999{
5000 rb_len_t len, slen;
5001 const char *sbeg, *s;
5002 rb_encoding *enc;
5003
5004 enc = rb_enc_check(str, sub);
5005 if (is_broken_string(sub)) return -1;
5006 len = RSTRING_LEN(str);
5007 slen = RSTRING_LEN(sub);
5008
5009 /* substring longer than string */
5010 if (len < slen) return -1;
5011 if (len - pos < slen) pos = len - slen;
5012 if (len == 0) return pos;
5013
5014 sbeg = RSTRING_PTR(str);
5015
5016 if (pos == 0) {
5017 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
5018 return 0;
5019 else
5020 return -1;
5021 }
5022
5023 s = sbeg + pos;
5024 return str_rindex(str, sub, s, enc);
5025}
5026
5027/*
5028 * call-seq:
5029 * byterindex(object, offset = self.bytesize) -> integer or nil
5030 *
5031 * Returns the 0-based integer index of a substring of +self+
5032 * that is the _last_ match for the given +object+ (a string or Regexp) and +offset+,
5033 * or +nil+ if there is no such substring;
5034 * the returned index is the count of _bytes_ (not characters).
5035 *
5036 * When +object+ is a string,
5037 * returns the index of the _last_ found substring equal to +object+:
5038 *
5039 * s = 'foo' # => "foo"
5040 * s.size # => 3 # Three 1-byte characters.
5041 * s.bytesize # => 3 # Three bytes.
5042 * s.byterindex('f') # => 0
5043 * s.byterindex('o') # => 2
5044 * s.byterindex('oo') # => 1
5045 * s.byterindex('ooo') # => nil
5046 *
5047 * When +object+ is a Regexp,
5048 * returns the index of the last found substring matching +object+;
5049 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
5050 *
5051 * s = 'foo'
5052 * s.byterindex(/f/) # => 0
5053 * $~ # => #<MatchData "f">
5054 * s.byterindex(/o/) # => 2
5055 * s.byterindex(/oo/) # => 1
5056 * s.byterindex(/ooo/) # => nil
5057 * $~ # => nil
5058 *
5059 * The last match means starting at the possible last position,
5060 * not the last of the longest matches:
5061 *
5062 * s = 'foo'
5063 * s.byterindex(/o+/) # => 2
5064 * $~ #=> #<MatchData "o">
5065 *
5066 * To get the last longest match, use a negative lookbehind:
5067 *
5068 * s = 'foo'
5069 * s.byterindex(/(?<!o)o+/) # => 1
5070 * $~ # => #<MatchData "oo">
5071 *
5072 * Or use method #byteindex with negative lookahead:
5073 *
5074 * s = 'foo'
5075 * s.byteindex(/o+(?!.*o)/) # => 1
5076 * $~ #=> #<MatchData "oo">
5077 *
5078 * \Integer argument +offset+, if given, specifies the 0-based index
5079 * of the byte where searching is to end.
5080 *
5081 * When +offset+ is non-negative,
5082 * searching ends at byte position +offset+:
5083 *
5084 * s = 'foo'
5085 * s.byterindex('o', 0) # => nil
5086 * s.byterindex('o', 1) # => 1
5087 * s.byterindex('o', 2) # => 2
5088 * s.byterindex('o', 3) # => 2
5089 *
5090 * When +offset+ is negative, counts backward from the end of +self+:
5091 *
5092 * s = 'foo'
5093 * s.byterindex('o', -1) # => 2
5094 * s.byterindex('o', -2) # => 1
5095 * s.byterindex('o', -3) # => nil
5096 *
5097 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
5098 *
5099 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
5100 * s.size # => 2 # Two 3-byte characters.
5101 * s.bytesize # => 6 # Six bytes.
5102 * s.byterindex("\uFFFF") # => 3
5103 * s.byterindex("\uFFFF", 1) # Raises IndexError
5104 * s.byterindex("\uFFFF", 2) # Raises IndexError
5105 * s.byterindex("\uFFFF", 3) # => 3
5106 * s.byterindex("\uFFFF", 4) # Raises IndexError
5107 * s.byterindex("\uFFFF", 5) # Raises IndexError
5108 * s.byterindex("\uFFFF", 6) # => nil
5109 *
5110 * Related: see {Querying}[rdoc-ref:String@Querying].
5111 */
5112
5113static VALUE
5114rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
5115{
5116 VALUE sub;
5117 VALUE initpos;
5118 rb_len_t pos;
5119
5120 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
5121 pos = NUM2LEN(initpos);
5122 rb_len_t len = RSTRING_LEN(str);
5123 if (pos < 0 && (pos += len) < 0) {
5124 if (RB_TYPE_P(sub, T_REGEXP)) {
5126 }
5127 return Qnil;
5128 }
5129 if (pos > len) pos = len;
5130 }
5131 else {
5132 pos = RSTRING_LEN(str);
5133 }
5134
5135 str_ensure_byte_pos(str, pos);
5136
5137 if (RB_TYPE_P(sub, T_REGEXP)) {
5138 if (rb_reg_search(sub, str, pos, 1) >= 0) {
5139 VALUE match = rb_backref_get();
5140 pos = RMATCH_BEG(match, 0);
5141 return LEN2NUM(pos);
5142 }
5143 }
5144 else {
5145 StringValue(sub);
5146 pos = rb_str_byterindex(str, sub, pos);
5147 if (pos >= 0) return LEN2NUM(pos);
5148 }
5149 return Qnil;
5150}
5151
5152/*
5153 * call-seq:
5154 * self =~ other -> integer or nil
5155 *
5156 * When +other+ is a Regexp:
5157 *
5158 * - Returns the integer index (in characters) of the first match
5159 * for +self+ and +other+, or +nil+ if none;
5160 * - Updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
5161 *
5162 * Examples:
5163 *
5164 * 'foo' =~ /f/ # => 0
5165 * $~ # => #<MatchData "f">
5166 * 'foo' =~ /o/ # => 1
5167 * $~ # => #<MatchData "o">
5168 * 'foo' =~ /x/ # => nil
5169 * $~ # => nil
5170 *
5171 * Note that <tt>string =~ regexp</tt> is different from <tt>regexp =~ string</tt>
5172 * (see Regexp#=~):
5173 *
5174 * number = nil
5175 * 'no. 9' =~ /(?<number>\d+)/ # => 4
5176 * number # => nil # Not assigned.
5177 * /(?<number>\d+)/ =~ 'no. 9' # => 4
5178 * number # => "9" # Assigned.
5179 *
5180 * When +other+ is not a Regexp, returns the value
5181 * returned by <tt>other =~ self</tt>.
5182 *
5183 * Related: see {Querying}[rdoc-ref:String@Querying].
5184 */
5185
5186static VALUE
5187rb_str_match(VALUE x, VALUE y)
5188{
5189 switch (OBJ_BUILTIN_TYPE(y)) {
5190 case T_STRING:
5191 rb_raise(rb_eTypeError, "type mismatch: String given");
5192
5193 case T_REGEXP:
5194 return rb_reg_match(y, x);
5195
5196 default:
5197 return rb_funcall(y, idEqTilde, 1, x);
5198 }
5199}
5200
5201
5202static VALUE get_pat(VALUE);
5203
5204
5205/*
5206 * call-seq:
5207 * match(pattern, offset = 0) -> matchdata or nil
5208 * match(pattern, offset = 0) {|matchdata| ... } -> object
5209 *
5210 * Creates a MatchData object based on +self+ and the given arguments;
5211 * updates {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5212 *
5213 * - Computes +regexp+ by converting +pattern+ (if not already a Regexp).
5214 *
5215 * regexp = Regexp.new(pattern)
5216 *
5217 * - Calls <tt>regexp.match</tt> with +self+ to compute +matchdata+.
5218 * If +offset+ is given, it is also passed (see Regexp#match).
5219 *
5220 * With no block given, returns the computed +matchdata+ or +nil+:
5221 *
5222 * 'foo'.match('f') # => #<MatchData "f">
5223 * 'foo'.match('o') # => #<MatchData "o">
5224 * 'foo'.match('x') # => nil
5225 * 'foo'.match('f', 1) # => nil
5226 * 'foo'.match('o', 1) # => #<MatchData "o">
5227 *
5228 * With a block given and computed +matchdata+ non-nil, calls the block with +matchdata+;
5229 * returns the block's return value:
5230 *
5231 * 'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
5232 *
5233 * With a block given and +nil+ +matchdata+, does not call the block:
5234 *
5235 * 'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => nil
5236 *
5237 * Related: see {Querying}[rdoc-ref:String@Querying].
5238 */
5239
5240static VALUE
5241rb_str_match_m(int argc, VALUE *argv, VALUE str)
5242{
5243 VALUE re, result;
5244 if (argc < 1)
5245 rb_check_arity(argc, 1, 2);
5246 re = argv[0];
5247 argv[0] = str;
5248 result = rb_funcallv(get_pat(re), rb_intern("match"), argc, argv);
5249 if (!NIL_P(result) && rb_block_given_p()) {
5250 return rb_yield(result);
5251 }
5252 return result;
5253}
5254
5255/*
5256 * call-seq:
5257 * match?(pattern, offset = 0) -> true or false
5258 *
5259 * Returns whether a match is found for +self+ and the given arguments;
5260 * does not update {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5261 *
5262 * Computes +regexp+ by converting +pattern+ (if not already a Regexp):
5263 *
5264 * regexp = Regexp.new(pattern)
5265 *
5266 * The search for +regexp+ in +self+ begins at the given character +offset+.
5267 * Returns +true+ if a match is found, +false+ otherwise:
5268 *
5269 * 'foo'.match?(/o/) # => true
5270 * 'foo'.match?('o') # => true
5271 * 'foo'.match?(/x/) # => false
5272 * 'foo'.match?('f', 1) # => false
5273 * 'foo'.match?('o', 1) # => true
5274 *
5275 * Related: see {Querying}[rdoc-ref:String@Querying].
5276 */
5277
5278static VALUE
5279rb_str_match_m_p(int argc, VALUE *argv, VALUE str)
5280{
5281 VALUE re;
5282 rb_check_arity(argc, 1, 2);
5283 re = get_pat(argv[0]);
5284 return rb_reg_match_p(re, str, argc > 1 ? NUM2LEN(argv[1]) : 0);
5285}
5286
5287enum neighbor_char {
5288 NEIGHBOR_NOT_CHAR,
5289 NEIGHBOR_FOUND,
5290 NEIGHBOR_WRAPPED
5291};
5292
5293static enum neighbor_char
5294enc_succ_char(char *p, rb_len_t len, rb_encoding *enc)
5295{
5296 rb_len_t i;
5297 int l;
5298
5299 if (rb_enc_mbminlen(enc) > 1) {
5300 /* wchar, trivial case */
5301 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5302 if (!MBCLEN_CHARFOUND_P(r)) {
5303 return NEIGHBOR_NOT_CHAR;
5304 }
5305 c = rb_enc_mbc_to_codepoint(p, p + len, enc) + 1;
5306 l = rb_enc_code_to_mbclen(c, enc);
5307 if (!l) return NEIGHBOR_NOT_CHAR;
5308 if (l != len) return NEIGHBOR_WRAPPED;
5309 rb_enc_mbcput(c, p, enc);
5310 r = rb_enc_precise_mbclen(p, p + len, enc);
5311 if (!MBCLEN_CHARFOUND_P(r)) {
5312 return NEIGHBOR_NOT_CHAR;
5313 }
5314 return NEIGHBOR_FOUND;
5315 }
5316 while (1) {
5317 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0xff; i--)
5318 p[i] = '\0';
5319 if (i < 0)
5320 return NEIGHBOR_WRAPPED;
5321 ++((unsigned char*)p)[i];
5322 l = rb_enc_precise_mbclen(p, p+len, enc);
5323 if (MBCLEN_CHARFOUND_P(l)) {
5324 l = MBCLEN_CHARFOUND_LEN(l);
5325 if (l == len) {
5326 return NEIGHBOR_FOUND;
5327 }
5328 else {
5329 memset(p+l, 0xff, len-l);
5330 }
5331 }
5332 if (MBCLEN_INVALID_P(l) && i < len-1) {
5333 rb_len_t len2;
5334 int l2;
5335 for (len2 = len-1; 0 < len2; len2--) {
5336 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5337 if (!MBCLEN_INVALID_P(l2))
5338 break;
5339 }
5340 memset(p+len2+1, 0xff, len-(len2+1));
5341 }
5342 }
5343}
5344
5345static enum neighbor_char
5346enc_pred_char(char *p, rb_len_t len, rb_encoding *enc)
5347{
5348 rb_len_t i;
5349 int l;
5350 if (rb_enc_mbminlen(enc) > 1) {
5351 /* wchar, trivial case */
5352 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5353 if (!MBCLEN_CHARFOUND_P(r)) {
5354 return NEIGHBOR_NOT_CHAR;
5355 }
5356 c = rb_enc_mbc_to_codepoint(p, p + len, enc);
5357 if (!c) return NEIGHBOR_NOT_CHAR;
5358 --c;
5359 l = rb_enc_code_to_mbclen(c, enc);
5360 if (!l) return NEIGHBOR_NOT_CHAR;
5361 if (l != len) return NEIGHBOR_WRAPPED;
5362 rb_enc_mbcput(c, p, enc);
5363 r = rb_enc_precise_mbclen(p, p + len, enc);
5364 if (!MBCLEN_CHARFOUND_P(r)) {
5365 return NEIGHBOR_NOT_CHAR;
5366 }
5367 return NEIGHBOR_FOUND;
5368 }
5369 while (1) {
5370 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0; i--)
5371 p[i] = '\xff';
5372 if (i < 0)
5373 return NEIGHBOR_WRAPPED;
5374 --((unsigned char*)p)[i];
5375 l = rb_enc_precise_mbclen(p, p+len, enc);
5376 if (MBCLEN_CHARFOUND_P(l)) {
5377 l = MBCLEN_CHARFOUND_LEN(l);
5378 if (l == len) {
5379 return NEIGHBOR_FOUND;
5380 }
5381 else {
5382 memset(p+l, 0, len-l);
5383 }
5384 }
5385 if (MBCLEN_INVALID_P(l) && i < len-1) {
5386 rb_len_t len2;
5387 int l2;
5388 for (len2 = len-1; 0 < len2; len2--) {
5389 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5390 if (!MBCLEN_INVALID_P(l2))
5391 break;
5392 }
5393 memset(p+len2+1, 0, len-(len2+1));
5394 }
5395 }
5396}
5397
5398/*
5399 overwrite +p+ by succeeding letter in +enc+ and returns
5400 NEIGHBOR_FOUND or NEIGHBOR_WRAPPED.
5401 When NEIGHBOR_WRAPPED, carried-out letter is stored into carry.
5402 assuming each ranges are successive, and mbclen
5403 never change in each ranges.
5404 NEIGHBOR_NOT_CHAR is returned if invalid character or the range has only one
5405 character.
5406 */
5407static enum neighbor_char
5408enc_succ_alnum_char(char *p, rb_len_t len, rb_encoding *enc, char *carry)
5409{
5410 enum neighbor_char ret;
5411 unsigned int c;
5412 int ctype;
5413 int range;
5414 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5415
5416 /* skip 03A2, invalid char between GREEK CAPITAL LETTERS */
5417 int try;
5418 const int max_gaps = 1;
5419
5420 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5421 if (rb_enc_isctype(c, ONIGENC_CTYPE_DIGIT, enc))
5422 ctype = ONIGENC_CTYPE_DIGIT;
5423 else if (rb_enc_isctype(c, ONIGENC_CTYPE_ALPHA, enc))
5424 ctype = ONIGENC_CTYPE_ALPHA;
5425 else
5426 return NEIGHBOR_NOT_CHAR;
5427
5428 MEMCPY(save, p, char, len);
5429 for (try = 0; try <= max_gaps; ++try) {
5430 ret = enc_succ_char(p, len, enc);
5431 if (ret == NEIGHBOR_FOUND) {
5432 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5433 if (rb_enc_isctype(c, ctype, enc))
5434 return NEIGHBOR_FOUND;
5435 }
5436 }
5437 MEMCPY(p, save, char, len);
5438 range = 1;
5439 while (1) {
5440 MEMCPY(save, p, char, len);
5441 ret = enc_pred_char(p, len, enc);
5442 if (ret == NEIGHBOR_FOUND) {
5443 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5444 if (!rb_enc_isctype(c, ctype, enc)) {
5445 MEMCPY(p, save, char, len);
5446 break;
5447 }
5448 }
5449 else {
5450 MEMCPY(p, save, char, len);
5451 break;
5452 }
5453 range++;
5454 }
5455 if (range == 1) {
5456 return NEIGHBOR_NOT_CHAR;
5457 }
5458
5459 if (ctype != ONIGENC_CTYPE_DIGIT) {
5460 MEMCPY(carry, p, char, len);
5461 return NEIGHBOR_WRAPPED;
5462 }
5463
5464 MEMCPY(carry, p, char, len);
5465 enc_succ_char(carry, len, enc);
5466 return NEIGHBOR_WRAPPED;
5467}
5468
5469
5470static VALUE str_succ(VALUE str);
5471
5472/*
5473 * call-seq:
5474 * succ -> new_str
5475 *
5476 * :include: doc/string/succ.rdoc
5477 *
5478 */
5479
5480VALUE
5482{
5483 VALUE str;
5484 str = rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5485 rb_enc_cr_str_copy_for_substr(str, orig);
5486 return str_succ(str);
5487}
5488
5489static VALUE
5490str_succ(VALUE str)
5491{
5492 rb_encoding *enc;
5493 char *sbeg, *s, *e, *last_alnum = 0;
5494 int found_alnum = 0;
5495 rb_len_t l, slen;
5496 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] = "\1";
5497 rb_len_t carry_pos = 0, carry_len = 1;
5498 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5499
5500 slen = RSTRING_LEN(str);
5501 if (slen == 0) return str;
5502
5503 enc = STR_ENC_GET(str);
5504 sbeg = RSTRING_PTR(str);
5505 s = e = sbeg + slen;
5506
5507 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5508 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5509 if (ISALPHA(*last_alnum) ? ISDIGIT(*s) :
5510 ISDIGIT(*last_alnum) ? ISALPHA(*s) : 0) {
5511 break;
5512 }
5513 }
5514 l = rb_enc_precise_mbclen(s, e, enc);
5515 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5516 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5517 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5518 switch (neighbor) {
5519 case NEIGHBOR_NOT_CHAR:
5520 continue;
5521 case NEIGHBOR_FOUND:
5522 return str;
5523 case NEIGHBOR_WRAPPED:
5524 last_alnum = s;
5525 break;
5526 }
5527 found_alnum = 1;
5528 carry_pos = s - sbeg;
5529 carry_len = l;
5530 }
5531 if (!found_alnum) { /* str contains no alnum */
5532 s = e;
5533 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5534 enum neighbor_char neighbor;
5535 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5536 l = rb_enc_precise_mbclen(s, e, enc);
5537 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5538 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5539 MEMCPY(tmp, s, char, l);
5540 neighbor = enc_succ_char(tmp, l, enc);
5541 switch (neighbor) {
5542 case NEIGHBOR_FOUND:
5543 MEMCPY(s, tmp, char, l);
5544 return str;
5545 break;
5546 case NEIGHBOR_WRAPPED:
5547 MEMCPY(s, tmp, char, l);
5548 break;
5549 case NEIGHBOR_NOT_CHAR:
5550 break;
5551 }
5552 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5553 /* wrapped to \0...\0. search next valid char. */
5554 enc_succ_char(s, l, enc);
5555 }
5556 if (!rb_enc_asciicompat(enc)) {
5557 MEMCPY(carry, s, char, l);
5558 carry_len = l;
5559 }
5560 carry_pos = s - sbeg;
5561 }
5563 }
5564 RESIZE_CAPA(str, slen + carry_len);
5565 sbeg = RSTRING_PTR(str);
5566 s = sbeg + carry_pos;
5567 memmove(s + carry_len, s, slen - carry_pos);
5568 memmove(s, carry, carry_len);
5569 slen += carry_len;
5570 STR_SET_LEN(str, slen);
5571 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5572 rb_enc_str_coderange(str);
5573 return str;
5574}
5575
5576
5577/*
5578 * call-seq:
5579 * succ! -> self
5580 *
5581 * Like String#succ, but modifies +self+ in place; returns +self+.
5582 *
5583 * Related: see {Modifying}[rdoc-ref:String@Modifying].
5584 */
5585
5586static VALUE
5587rb_str_succ_bang(VALUE str)
5588{
5589 rb_str_modify(str);
5590 str_succ(str);
5591 return str;
5592}
5593
5594static int
5595all_digits_p(const char *s, rb_len_t len)
5596{
5597 while (len-- > 0) {
5598 if (!ISDIGIT(*s)) return 0;
5599 s++;
5600 }
5601 return 1;
5602}
5603
5604static int
5605str_upto_i(VALUE str, VALUE arg)
5606{
5607 rb_yield(str);
5608 return 0;
5609}
5610
5611/*
5612 * call-seq:
5613 * upto(other_string, exclusive = false) {|string| ... } -> self
5614 * upto(other_string, exclusive = false) -> new_enumerator
5615 *
5616 * :include: doc/string/upto.rdoc
5617 *
5618 */
5619
5620static VALUE
5621rb_str_upto(int argc, VALUE *argv, VALUE beg)
5622{
5623 VALUE end, exclusive;
5624
5625 rb_scan_args(argc, argv, "11", &end, &exclusive);
5626 RETURN_ENUMERATOR(beg, argc, argv);
5627 return rb_str_upto_each(beg, end, RTEST(exclusive), str_upto_i, Qnil);
5628}
5629
5630VALUE
5631rb_str_upto_each(VALUE beg, VALUE end, int excl, int (*each)(VALUE, VALUE), VALUE arg)
5632{
5633 VALUE current, after_end;
5634 ID succ;
5635 int n, ascii;
5636 rb_encoding *enc;
5637
5638 CONST_ID(succ, "succ");
5639 StringValue(end);
5640 enc = rb_enc_check(beg, end);
5641 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5642 /* single character */
5643 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5644 char c = RSTRING_PTR(beg)[0];
5645 char e = RSTRING_PTR(end)[0];
5646
5647 if (c > e || (excl && c == e)) return beg;
5648 for (;;) {
5649 VALUE str = rb_enc_str_new(&c, 1, enc);
5651 if ((*each)(str, arg)) break;
5652 if (!excl && c == e) break;
5653 c++;
5654 if (excl && c == e) break;
5655 }
5656 return beg;
5657 }
5658 /* both edges are all digits */
5659 if (ascii && ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
5660 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5661 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5662 VALUE b, e;
5663 int width;
5664
5665 width = RSTRING_LENINT(beg);
5666 b = rb_str_to_inum(beg, 10, FALSE);
5667 e = rb_str_to_inum(end, 10, FALSE);
5668 if (FIXNUM_P(b) && FIXNUM_P(e)) {
5669 long bi = FIX2LONG(b);
5670 long ei = FIX2LONG(e);
5671 rb_encoding *usascii = rb_usascii_encoding();
5672
5673 while (bi <= ei) {
5674 if (excl && bi == ei) break;
5675 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5676 bi++;
5677 }
5678 }
5679 else {
5680 ID op = excl ? '<' : idLE;
5681 VALUE args[2], fmt = rb_fstring_lit("%.*d");
5682
5683 args[0] = INT2FIX(width);
5684 while (rb_funcall(b, op, 1, e)) {
5685 args[1] = b;
5686 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5687 b = rb_funcallv(b, succ, 0, 0);
5688 }
5689 }
5690 return beg;
5691 }
5692 /* normal case */
5693 n = rb_str_cmp(beg, end);
5694 if (n > 0 || (excl && n == 0)) return beg;
5695
5696 after_end = rb_funcallv(end, succ, 0, 0);
5697 current = str_duplicate(rb_cString, beg);
5698 while (!rb_str_equal(current, after_end)) {
5699 VALUE next = Qnil;
5700 if (excl || !rb_str_equal(current, end))
5701 next = rb_funcallv(current, succ, 0, 0);
5702 if ((*each)(current, arg)) break;
5703 if (NIL_P(next)) break;
5704 current = next;
5705 StringValue(current);
5706 if (excl && rb_str_equal(current, end)) break;
5707 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5708 break;
5709 }
5710
5711 return beg;
5712}
5713
5714VALUE
5715rb_str_upto_endless_each(VALUE beg, int (*each)(VALUE, VALUE), VALUE arg)
5716{
5717 VALUE current;
5718 ID succ;
5719
5720 CONST_ID(succ, "succ");
5721 /* both edges are all digits */
5722 if (is_ascii_string(beg) && ISDIGIT(RSTRING_PTR(beg)[0]) &&
5723 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5724 VALUE b, args[2], fmt = rb_fstring_lit("%.*d");
5725 int width = RSTRING_LENINT(beg);
5726 b = rb_str_to_inum(beg, 10, FALSE);
5727 if (FIXNUM_P(b)) {
5728 long bi = FIX2LONG(b);
5729 rb_encoding *usascii = rb_usascii_encoding();
5730
5731 while (FIXABLE(bi)) {
5732 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5733 bi++;
5734 }
5735 b = LONG2NUM(bi);
5736 }
5737 args[0] = INT2FIX(width);
5738 while (1) {
5739 args[1] = b;
5740 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5741 b = rb_funcallv(b, succ, 0, 0);
5742 }
5743 }
5744 /* normal case */
5745 current = str_duplicate(rb_cString, beg);
5746 while (1) {
5747 VALUE next = rb_funcallv(current, succ, 0, 0);
5748 if ((*each)(current, arg)) break;
5749 current = next;
5750 StringValue(current);
5751 if (RSTRING_LEN(current) == 0)
5752 break;
5753 }
5754
5755 return beg;
5756}
5757
5758static int
5759include_range_i(VALUE str, VALUE arg)
5760{
5761 VALUE *argp = (VALUE *)arg;
5762 if (!rb_equal(str, *argp)) return 0;
5763 *argp = Qnil;
5764 return 1;
5765}
5766
5767VALUE
5768rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive)
5769{
5770 beg = rb_str_new_frozen(beg);
5771 StringValue(end);
5772 end = rb_str_new_frozen(end);
5773 if (NIL_P(val)) return Qfalse;
5774 val = rb_check_string_type(val);
5775 if (NIL_P(val)) return Qfalse;
5776 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5777 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5778 rb_enc_asciicompat(STR_ENC_GET(val))) {
5779 const char *bp = RSTRING_PTR(beg);
5780 const char *ep = RSTRING_PTR(end);
5781 const char *vp = RSTRING_PTR(val);
5782 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5783 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5784 return Qfalse;
5785 else {
5786 char b = *bp;
5787 char e = *ep;
5788 char v = *vp;
5789
5790 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
5791 if (b <= v && v < e) return Qtrue;
5792 return RBOOL(!RTEST(exclusive) && b <= v && v == e);
5793 }
5794 }
5795 }
5796#if 0
5797 /* both edges are all digits */
5798 if (ISDIGIT(*bp) && ISDIGIT(*ep) &&
5799 all_digits_p(bp, RSTRING_LEN(beg)) &&
5800 all_digits_p(ep, RSTRING_LEN(end))) {
5801 /* TODO */
5802 }
5803#endif
5804 }
5805 rb_str_upto_each(beg, end, RTEST(exclusive), include_range_i, (VALUE)&val);
5806
5807 return RBOOL(NIL_P(val));
5808}
5809
5810static VALUE
5811rb_str_subpat(VALUE str, VALUE re, VALUE backref)
5812{
5813 if (rb_reg_search(re, str, 0, 0) >= 0) {
5814 VALUE match = rb_backref_get();
5815 int nth = rb_reg_backref_number(match, backref);
5816 return rb_reg_nth_match(nth, match);
5817 }
5818 return Qnil;
5819}
5820
5821static VALUE
5822rb_str_aref(VALUE str, VALUE indx)
5823{
5824 rb_len_t idx;
5825
5826 if (FIXNUM_P(indx)) {
5827 idx = FIX2LONG(indx);
5828 }
5829 else if (RB_TYPE_P(indx, T_REGEXP)) {
5830 return rb_str_subpat(str, indx, INT2FIX(0));
5831 }
5832 else if (RB_TYPE_P(indx, T_STRING)) {
5833 if (rb_str_index(str, indx, 0) != -1)
5834 return str_duplicate(rb_cString, indx);
5835 return Qnil;
5836 }
5837 else {
5838 /* check if indx is Range */
5839 rb_len_t beg, len = str_strlen(str, NULL);
5840 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
5841 case Qfalse:
5842 break;
5843 case Qnil:
5844 return Qnil;
5845 default:
5846 return rb_str_substr(str, beg, len);
5847 }
5848 idx = NUM2LEN(indx);
5849 }
5850
5851 return str_substr(str, idx, 1, FALSE);
5852}
5853
5854
5855/*
5856 * call-seq:
5857 * self[offset] -> new_string or nil
5858 * self[offset, size] -> new_string or nil
5859 * self[range] -> new_string or nil
5860 * self[regexp, capture = 0] -> new_string or nil
5861 * self[substring] -> new_string or nil
5862 *
5863 * :include: doc/string/aref.rdoc
5864 *
5865 */
5866
5867static VALUE
5868rb_str_aref_m(int argc, VALUE *argv, VALUE str)
5869{
5870 if (argc == 2) {
5871 if (RB_TYPE_P(argv[0], T_REGEXP)) {
5872 return rb_str_subpat(str, argv[0], argv[1]);
5873 }
5874 else {
5875 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5876 }
5877 }
5878 rb_check_arity(argc, 1, 2);
5879 return rb_str_aref(str, argv[0]);
5880}
5881
5882VALUE
5884{
5885 char *ptr = RSTRING_PTR(str);
5886 rb_len_t olen = RSTRING_LEN(str), nlen;
5887
5888 str_modifiable(str);
5889 if (len > olen) len = olen;
5890 nlen = olen - len;
5891 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5892 char *oldptr = ptr;
5893 size_t old_capa = RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5894 int fl = (int)(RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5895 STR_SET_EMBED(str);
5896 ptr = RSTRING(str)->as.embed.ary;
5897 memmove(ptr, oldptr + len, nlen);
5898 if (fl == STR_NOEMBED) {
5899 SIZED_FREE_N(oldptr, old_capa);
5900 }
5901 }
5902 else {
5903 if (!STR_SHARED_P(str)) {
5904 VALUE shared = heap_str_make_shared(rb_obj_class(str), str, TERM_LEN(str));
5905 rb_enc_cr_str_exact_copy(shared, str);
5907 }
5908 ptr = RSTRING(str)->as.heap.ptr += len;
5909 }
5910 STR_SET_LEN(str, nlen);
5911
5912 if (!SHARABLE_MIDDLE_SUBSTRING) {
5913 TERM_FILL(ptr + nlen, TERM_LEN(str));
5914 }
5916 return str;
5917}
5918
5919static void
5920rb_str_update_1(VALUE str, rb_len_t beg, rb_len_t len, VALUE val, rb_len_t vbeg, rb_len_t vlen)
5921{
5922 char *sptr;
5923 rb_len_t slen;
5924 int cr;
5925
5926 if (beg == 0 && vlen == 0) {
5927 rb_str_drop_bytes(str, len);
5928 return;
5929 }
5930
5931 str_modify_keep_cr(str);
5932 RSTRING_GETMEM(str, sptr, slen);
5933 if (len < vlen) {
5934 /* expand string */
5935 RESIZE_CAPA(str, slen + vlen - len);
5936 sptr = RSTRING_PTR(str);
5937 }
5938
5940 cr = rb_enc_str_coderange(val);
5941 else
5943
5944 if (vlen != len) {
5945 memmove(sptr + beg + vlen,
5946 sptr + beg + len,
5947 slen - (beg + len));
5948 }
5949 if (vlen < beg && len < 0) {
5950 MEMZERO(sptr + slen, char, -len);
5951 }
5952 if (vlen > 0) {
5953 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5954 }
5955 slen += vlen - len;
5956 STR_SET_LEN(str, slen);
5957 TERM_FILL(&sptr[slen], TERM_LEN(str));
5958 ENC_CODERANGE_SET(str, cr);
5959}
5960
5961static inline void
5962rb_str_update_0(VALUE str, rb_len_t beg, rb_len_t len, VALUE val)
5963{
5964 rb_str_update_1(str, beg, len, val, 0, RSTRING_LEN(val));
5965}
5966
5967void
5969{
5970 rb_len_t slen;
5971 char *p, *e;
5972 rb_encoding *enc;
5973 int singlebyte = single_byte_optimizable(str);
5974 int cr;
5975
5976 if (len < 0) rb_raise(rb_eIndexError, "negative length %"PRIdLEN, len);
5977
5978 StringValue(val);
5979 enc = rb_enc_check(str, val);
5980 slen = str_strlen(str, enc); /* rb_enc_check */
5981
5982 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5983 rb_raise(rb_eIndexError, "index %"PRIdLEN" out of string", beg);
5984 }
5985 if (beg < 0) {
5986 beg += slen;
5987 }
5988 RUBY_ASSERT(beg >= 0);
5989 RUBY_ASSERT(beg <= slen);
5990
5991 if (len > slen - beg) {
5992 len = slen - beg;
5993 }
5994 p = str_nth(RSTRING_PTR(str), RSTRING_END(str), beg, enc, singlebyte);
5995 if (!p) p = RSTRING_END(str);
5996 e = str_nth(p, RSTRING_END(str), len, enc, singlebyte);
5997 if (!e) e = RSTRING_END(str);
5998 /* error check */
5999 beg = p - RSTRING_PTR(str); /* physical position */
6000 len = e - p; /* physical length */
6001 rb_str_update_0(str, beg, len, val);
6002 rb_enc_associate(str, enc);
6004 if (cr != ENC_CODERANGE_BROKEN)
6005 ENC_CODERANGE_SET(str, cr);
6006}
6007
6008static void
6009rb_str_subpat_set(VALUE str, VALUE re, VALUE backref, VALUE val)
6010{
6011 int nth;
6012 VALUE match;
6013 rb_len_t start, end, len;
6014 rb_encoding *enc;
6015
6016 if (rb_reg_search(re, str, 0, 0) < 0) {
6017 rb_raise(rb_eIndexError, "regexp not matched");
6018 }
6019 match = rb_backref_get();
6020 nth = rb_reg_backref_number(match, backref);
6021 int num_regs = RMATCH_NREGS(match); /* 1 <= num_regs <= ONIG_MAX_CAPTURE_GROUP_NUM (= 32767) */
6022 if (nth >= num_regs || nth + num_regs <= 0) {
6023 rb_raise(rb_eIndexError, "index %d out of regexp", nth);
6024 }
6025 if (nth < 0) {
6026 nth += num_regs;
6027 }
6028
6029 start = RMATCH_BEG(match, nth);
6030 if (start == -1) {
6031 rb_raise(rb_eIndexError, "regexp group %d not matched", nth);
6032 }
6033 end = RMATCH_END(match, nth);
6034 len = end - start;
6035
6036 StringValue(val);
6037 if (start + len > RSTRING_LEN(str)) {
6038 rb_raise(rb_eRuntimeError, "string modified");
6039 }
6040
6041 enc = rb_enc_check_str(str, val);
6042 rb_str_update_0(str, start, len, val);
6043 rb_enc_associate(str, enc);
6044}
6045
6046static VALUE
6047rb_str_aset(VALUE str, VALUE indx, VALUE val)
6048{
6049 rb_len_t idx, beg;
6050
6051 switch (TYPE(indx)) {
6052 case T_REGEXP:
6053 rb_str_subpat_set(str, indx, INT2FIX(0), val);
6054 return val;
6055
6056 case T_STRING:
6057 beg = rb_str_index(str, indx, 0);
6058 if (beg < 0) {
6059 rb_raise(rb_eIndexError, "string not matched");
6060 }
6061 beg = rb_str_sublen(str, beg);
6062 rb_str_update(str, beg, str_strlen(indx, NULL), val);
6063 return val;
6064
6065 default:
6066 /* check if indx is Range */
6067 {
6068 rb_len_t beg, len;
6069 if (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 2)) {
6070 rb_str_update(str, beg, len, val);
6071 return val;
6072 }
6073 }
6074 /* FALLTHROUGH */
6075
6076 case T_FIXNUM:
6077 idx = NUM2LEN(indx);
6078 rb_str_update(str, idx, 1, val);
6079 return val;
6080 }
6081}
6082
6083/*
6084 * call-seq:
6085 * self[index] = other_string -> new_string
6086 * self[start, length] = other_string -> new_string
6087 * self[range] = other_string -> new_string
6088 * self[regexp, capture = 0] = other_string -> new_string
6089 * self[substring] = other_string -> new_string
6090 *
6091 * :include: doc/string/aset.rdoc
6092 *
6093 */
6094
6095static VALUE
6096rb_str_aset_m(int argc, VALUE *argv, VALUE str)
6097{
6098 if (argc == 3) {
6099 if (RB_TYPE_P(argv[0], T_REGEXP)) {
6100 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6101 }
6102 else {
6103 rb_str_update(str, NUM2LEN(argv[0]), NUM2LEN(argv[1]), argv[2]);
6104 }
6105 return argv[2];
6106 }
6107 rb_check_arity(argc, 2, 3);
6108 return rb_str_aset(str, argv[0], argv[1]);
6109}
6110
6111/*
6112 * call-seq:
6113 * insert(offset, other_string) -> self
6114 *
6115 * :include: doc/string/insert.rdoc
6116 *
6117 */
6118
6119static VALUE
6120rb_str_insert(VALUE str, VALUE idx, VALUE str2)
6121{
6122 rb_len_t pos = NUM2LEN(idx);
6123
6124 if (pos == -1) {
6125 return rb_str_append(str, str2);
6126 }
6127 else if (pos < 0) {
6128 pos++;
6129 }
6130 rb_str_update(str, pos, 0, str2);
6131 return str;
6132}
6133
6134
6135/*
6136 * call-seq:
6137 * slice!(index) -> new_string or nil
6138 * slice!(start, length) -> new_string or nil
6139 * slice!(range) -> new_string or nil
6140 * slice!(regexp, capture = 0) -> new_string or nil
6141 * slice!(substring) -> new_string or nil
6142 *
6143 * Like String#[] (and its alias String#slice), except that:
6144 *
6145 * - Performs substitutions in +self+ (not in a copy of +self+).
6146 * - Returns the removed substring if any modifications were made, +nil+ otherwise.
6147 *
6148 * A few examples:
6149 *
6150 * s = 'hello'
6151 * s.slice!('e') # => "e"
6152 * s # => "hllo"
6153 * s.slice!('e') # => nil
6154 * s # => "hllo"
6155 *
6156 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6157 */
6158
6159static VALUE
6160rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
6161{
6162 VALUE result = Qnil;
6163 VALUE indx;
6164 rb_len_t beg, len = 1;
6165 char *p;
6166
6167 rb_check_arity(argc, 1, 2);
6168 str_modify_keep_cr(str);
6169 indx = argv[0];
6170 if (RB_TYPE_P(indx, T_REGEXP)) {
6171 if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
6172 VALUE match = rb_backref_get();
6173 int num_regs = RMATCH_NREGS(match);
6174 int nth = 0;
6175 if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
6176 if ((nth += num_regs) <= 0) return Qnil;
6177 }
6178 else if (nth >= num_regs) return Qnil;
6179 beg = RMATCH_BEG(match, nth);
6180 len = RMATCH_END(match, nth) - beg;
6181 /* Converting the backref may have modified the string. */
6182 if (beg > RSTRING_LEN(str)) return Qnil;
6183 if (len > RSTRING_LEN(str) - beg) len = RSTRING_LEN(str) - beg;
6184 goto subseq;
6185 }
6186 else if (argc == 2) {
6187 beg = NUM2LEN(indx);
6188 len = NUM2LEN(argv[1]);
6189 goto num_index;
6190 }
6191 else if (FIXNUM_P(indx)) {
6192 beg = FIX2LONG(indx);
6193 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6194 if (!len) return Qnil;
6195 beg = p - RSTRING_PTR(str);
6196 goto subseq;
6197 }
6198 else if (RB_TYPE_P(indx, T_STRING)) {
6199 beg = rb_str_index(str, indx, 0);
6200 if (beg == -1) return Qnil;
6201 len = RSTRING_LEN(indx);
6202 result = str_duplicate(rb_cString, indx);
6203 goto squash;
6204 }
6205 else {
6206 switch (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 0)) {
6207 case Qnil:
6208 return Qnil;
6209 case Qfalse:
6210 beg = NUM2LEN(indx);
6211 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6212 if (!len) return Qnil;
6213 beg = p - RSTRING_PTR(str);
6214 goto subseq;
6215 default:
6216 goto num_index;
6217 }
6218 }
6219
6220 num_index:
6221 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6222 beg = p - RSTRING_PTR(str);
6223
6224 subseq:
6225 result = rb_str_new(RSTRING_PTR(str)+beg, len);
6226 rb_enc_cr_str_copy_for_substr(result, str);
6227
6228 squash:
6229 if (len > 0) {
6230 if (beg == 0) {
6231 rb_str_drop_bytes(str, len);
6232 }
6233 else {
6234 char *sptr = RSTRING_PTR(str);
6235 rb_len_t slen = RSTRING_LEN(str);
6236 if (beg + len > slen) /* pathological check */
6237 len = slen - beg;
6238 memmove(sptr + beg,
6239 sptr + beg + len,
6240 slen - (beg + len));
6241 slen -= len;
6242 STR_SET_LEN(str, slen);
6243 TERM_FILL(&sptr[slen], TERM_LEN(str));
6244 }
6245 }
6246 return result;
6247}
6248
6249static VALUE
6250get_pat(VALUE pat)
6251{
6252 VALUE val;
6253
6254 switch (OBJ_BUILTIN_TYPE(pat)) {
6255 case T_REGEXP:
6256 return pat;
6257
6258 case T_STRING:
6259 break;
6260
6261 default:
6262 val = rb_check_string_type(pat);
6263 if (NIL_P(val)) {
6264 Check_Type(pat, T_REGEXP);
6265 }
6266 pat = val;
6267 }
6268
6269 return rb_reg_regcomp(pat);
6270}
6271
6272static VALUE
6273get_pat_quoted(VALUE pat, int check)
6274{
6275 VALUE val;
6276
6277 switch (OBJ_BUILTIN_TYPE(pat)) {
6278 case T_REGEXP:
6279 return pat;
6280
6281 case T_STRING:
6282 break;
6283
6284 default:
6285 val = rb_check_string_type(pat);
6286 if (NIL_P(val)) {
6287 Check_Type(pat, T_REGEXP);
6288 }
6289 pat = val;
6290 }
6291 if (check && is_broken_string(pat)) {
6292 rb_exc_raise(rb_reg_check_preprocess(pat));
6293 }
6294 return pat;
6295}
6296
6297static rb_len_t
6298rb_pat_search0(VALUE pat, VALUE str, rb_len_t pos, int set_backref_str, VALUE *match)
6299{
6300 if (BUILTIN_TYPE(pat) == T_STRING) {
6301 pos = rb_str_byteindex(str, pat, pos);
6302 if (set_backref_str) {
6303 if (pos >= 0) {
6304 str = rb_str_new_frozen_String(str);
6305 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6306 if (match) {
6307 *match = match_data;
6308 }
6309 }
6310 else {
6312 }
6313 }
6314 return pos;
6315 }
6316 else {
6317 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6318 }
6319}
6320
6321static rb_len_t
6322rb_pat_search(VALUE pat, VALUE str, rb_len_t pos, int set_backref_str)
6323{
6324 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6325}
6326
6327
6328/*
6329 * call-seq:
6330 * sub!(pattern, replacement) -> self or nil
6331 * sub!(pattern) {|match| ... } -> self or nil
6332 *
6333 * Like String#sub, except that:
6334 *
6335 * - Changes are made to +self+, not to copy of +self+.
6336 * - Returns +self+ if any changes are made, +nil+ otherwise.
6337 *
6338 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6339 */
6340
6341static VALUE
6342rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
6343{
6344 VALUE pat, repl, hash = Qnil;
6345 int iter = 0;
6346 rb_len_t plen;
6347 int min_arity = rb_block_given_p() ? 1 : 2;
6348 rb_len_t beg;
6349
6350 rb_check_arity(argc, min_arity, 2);
6351 if (argc == 1) {
6352 iter = 1;
6353 }
6354 else {
6355 repl = argv[1];
6356 if (!RB_TYPE_P(repl, T_STRING)) {
6357 hash = rb_check_hash_type(repl);
6358 if (NIL_P(hash)) {
6359 StringValue(repl);
6360 }
6361 }
6362 }
6363
6364 pat = get_pat_quoted(argv[0], 1);
6365
6366 str_modifiable(str);
6367 beg = rb_pat_search(pat, str, 0, 1);
6368 if (beg >= 0) {
6369 rb_encoding *enc;
6370 int cr = ENC_CODERANGE(str);
6371 rb_len_t beg0, end0;
6372 VALUE match, match0 = Qnil;
6373 char *p, *rp;
6374 rb_len_t len, rlen;
6375
6376 match = rb_backref_get();
6377 if (RB_TYPE_P(pat, T_STRING)) {
6378 beg0 = beg;
6379 end0 = beg0 + RSTRING_LEN(pat);
6380 match0 = pat;
6381 }
6382 else {
6383 beg0 = RMATCH_BEG(match, 0);
6384 end0 = RMATCH_END(match, 0);
6385 if (iter) match0 = rb_reg_nth_match(0, match);
6386 }
6387
6388 if (iter || !NIL_P(hash)) {
6389 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6390
6391 if (iter) {
6392 repl = rb_obj_as_string(rb_yield(match0));
6393 }
6394 else {
6395 repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0));
6396 repl = rb_obj_as_string(repl);
6397 }
6398 str_mod_check(str, p, len);
6399 rb_check_frozen(str);
6400 }
6401 else {
6402 repl = rb_reg_regsub_match(repl, str, match);
6403 }
6404
6405 enc = rb_enc_compatible(str, repl);
6406 if (!enc) {
6407 rb_encoding *str_enc = STR_ENC_GET(str);
6408 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6409 if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
6410 coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
6411 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
6412 rb_enc_inspect_name(str_enc),
6413 rb_enc_inspect_name(STR_ENC_GET(repl)));
6414 }
6415 enc = STR_ENC_GET(repl);
6416 }
6417 rb_str_modify(str);
6418 rb_enc_associate(str, enc);
6420 int cr2 = ENC_CODERANGE(repl);
6421 if (cr2 == ENC_CODERANGE_BROKEN ||
6422 (cr == ENC_CODERANGE_VALID && cr2 == ENC_CODERANGE_7BIT))
6424 else
6425 cr = cr2;
6426 }
6427 plen = end0 - beg0;
6428 rlen = RSTRING_LEN(repl);
6429 len = RSTRING_LEN(str);
6430 if (rlen > plen) {
6431 RESIZE_CAPA(str, len + rlen - plen);
6432 }
6433 p = RSTRING_PTR(str);
6434 if (rlen != plen) {
6435 memmove(p + beg0 + rlen, p + beg0 + plen, len - beg0 - plen);
6436 }
6437 rp = RSTRING_PTR(repl);
6438 memmove(p + beg0, rp, rlen);
6439 len += rlen - plen;
6440 STR_SET_LEN(str, len);
6441 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
6442 ENC_CODERANGE_SET(str, cr);
6443
6444 RB_GC_GUARD(match);
6445
6446 return str;
6447 }
6448 return Qnil;
6449}
6450
6451
6452/*
6453 * call-seq:
6454 * sub(pattern, replacement) -> new_string
6455 * sub(pattern) {|match| ... } -> new_string
6456 *
6457 * :include: doc/string/sub.rdoc
6458 */
6459
6460static VALUE
6461rb_str_sub(int argc, VALUE *argv, VALUE str)
6462{
6463 str = str_duplicate(rb_cString, str);
6464 rb_str_sub_bang(argc, argv, str);
6465 return str;
6466}
6467
6468static VALUE
6469str_gsub(int argc, VALUE *argv, VALUE str, int bang)
6470{
6471 VALUE pat, val = Qnil, repl, match0 = Qnil, dest, hash = Qnil, match = Qnil;
6472 rb_len_t beg, beg0, end0;
6473 rb_len_t offset, blen, slen, len, last;
6474 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6475 char *sp, *cp;
6476 int need_backref_str = -1;
6477 rb_encoding *str_enc;
6478
6479 switch (argc) {
6480 case 1:
6481 RETURN_ENUMERATOR(str, argc, argv);
6482 mode = ITER;
6483 break;
6484 case 2:
6485 repl = argv[1];
6486 if (!RB_TYPE_P(repl, T_STRING)) {
6487 hash = rb_check_hash_type(repl);
6488 if (NIL_P(hash)) {
6489 StringValue(repl);
6490 }
6491 else if (rb_hash_default_unredefined(hash) && !FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6492 mode = FAST_MAP;
6493 }
6494 else {
6495 mode = MAP;
6496 }
6497 }
6498 break;
6499 default:
6500 rb_error_arity(argc, 1, 2);
6501 }
6502
6503 pat = get_pat_quoted(argv[0], 1);
6504 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6505
6506 if (beg < 0) {
6507 if (bang) return Qnil; /* no match, no substitution */
6508 return str_duplicate(rb_cString, str);
6509 }
6510 if (bang) str_modify_keep_cr(str);
6511
6512 offset = 0;
6513 blen = RSTRING_LEN(str) + 30; /* len + margin */
6514 dest = rb_str_buf_new(blen);
6515 sp = RSTRING_PTR(str);
6516 slen = RSTRING_LEN(str);
6517 cp = sp;
6518 str_enc = STR_ENC_GET(str);
6519 rb_enc_associate(dest, str_enc);
6520 ENC_CODERANGE_SET(dest, rb_enc_asciicompat(str_enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
6521
6522 do {
6523 if (RB_TYPE_P(pat, T_STRING)) {
6524 beg0 = beg;
6525 end0 = beg0 + RSTRING_LEN(pat);
6526 match0 = pat;
6527 }
6528 else {
6529 beg0 = RMATCH_BEG(match, 0);
6530 end0 = RMATCH_END(match, 0);
6531 if (mode == ITER) match0 = rb_reg_nth_match(0, match);
6532 }
6533
6534 if (mode != STR) {
6535 if (mode == ITER) {
6536 val = rb_obj_as_string(rb_yield(match0));
6537 }
6538 else {
6539 struct RString fake_str = {RBASIC_INIT};
6540 VALUE key;
6541 if (mode == FAST_MAP) {
6542 // It is safe to use a fake_str here because we established that it won't escape,
6543 // as it's only used for `rb_hash_aref` and we checked the hash doesn't have a
6544 // default proc.
6545 key = setup_fake_str(&fake_str, sp + beg0, end0 - beg0, ENCODING_GET_INLINED(str));
6546 }
6547 else {
6548 key = rb_str_subseq(str, beg0, end0 - beg0);
6549 }
6550 val = rb_hash_aref(hash, key);
6551 val = rb_obj_as_string(val);
6552 }
6553 str_mod_check(str, sp, slen);
6554 if (val == dest) { /* paranoid check [ruby-dev:24827] */
6555 rb_raise(rb_eRuntimeError, "block should not cheat");
6556 }
6557 }
6558 else if (need_backref_str) {
6559 val = rb_reg_regsub_match(repl, str, match);
6560 if (need_backref_str < 0) {
6561 need_backref_str = val != repl;
6562 }
6563 }
6564 else {
6565 val = repl;
6566 }
6567
6568 len = beg0 - offset; /* copy pre-match substr */
6569 if (len) {
6570 rb_enc_str_buf_cat(dest, cp, len, str_enc);
6571 }
6572
6573 rb_str_buf_append(dest, val);
6574
6575 last = offset;
6576 offset = end0;
6577 if (beg0 == end0) {
6578 /*
6579 * Always consume at least one character of the input string
6580 * in order to prevent infinite loops.
6581 */
6582 if (RSTRING_LEN(str) <= end0) break;
6583 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0, RSTRING_END(str), str_enc);
6584 rb_enc_str_buf_cat(dest, RSTRING_PTR(str)+end0, len, str_enc);
6585 offset = end0 + len;
6586 }
6587 cp = RSTRING_PTR(str) + offset;
6588 if (offset > RSTRING_LEN(str)) break;
6589
6590 // In FAST_MAP and STR mode the backref can't escape so we can re-use the MatchData safely.
6591 if (mode != FAST_MAP && mode != STR) {
6592 match = Qnil;
6593 }
6594 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6595
6596 RB_GC_GUARD(match);
6597 } while (beg >= 0);
6598
6599 if (RSTRING_LEN(str) > offset) {
6600 rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
6601 }
6602 rb_pat_search0(pat, str, last, 1, &match);
6603 if (bang) {
6604 str_shared_replace(str, dest);
6605 }
6606 else {
6607 str = dest;
6608 }
6609
6610 return str;
6611}
6612
6613
6614/*
6615 * call-seq:
6616 * gsub!(pattern, replacement) -> self or nil
6617 * gsub!(pattern) {|match| ... } -> self or nil
6618 * gsub!(pattern) -> an_enumerator
6619 *
6620 * Like String#gsub, except that:
6621 *
6622 * - Performs substitutions in +self+ (not in a copy of +self+).
6623 * - Returns +self+ if any substitutions were performed, +nil+ otherwise.
6624 *
6625 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6626 */
6627
6628static VALUE
6629rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
6630{
6631 str_modifiable(str);
6632 return str_gsub(argc, argv, str, 1);
6633}
6634
6635
6636/*
6637 * call-seq:
6638 * gsub(pattern, replacement) -> new_string
6639 * gsub(pattern) {|match| ... } -> new_string
6640 * gsub(pattern) -> enumerator
6641 *
6642 * Returns a copy of +self+ with zero or more substrings replaced.
6643 *
6644 * Argument +pattern+ may be a string or a Regexp;
6645 * argument +replacement+ may be a string or a Hash.
6646 * Varying types for the argument values makes this method very versatile.
6647 *
6648 * Below are some simple examples;
6649 * for many more examples, see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
6650 *
6651 * With arguments +pattern+ and string +replacement+ given,
6652 * replaces each matching substring with the given +replacement+ string:
6653 *
6654 * s = 'abracadabra'
6655 * s.gsub('ab', 'AB') # => "ABracadABra"
6656 * s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
6657 *
6658 * With arguments +pattern+ and hash +replacement+ given,
6659 * replaces each matching substring with a value from the given +replacement+ hash,
6660 * or removes it:
6661 *
6662 * h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
6663 * s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
6664 * s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
6665 *
6666 * With argument +pattern+ and a block given,
6667 * calls the block with each matching substring;
6668 * replaces that substring with the block's return value:
6669 *
6670 * s.gsub(/[a-d]/) {|substring| substring.upcase }
6671 * # => "ABrACADABrA"
6672 *
6673 * With argument +pattern+ and no block given,
6674 * returns a new Enumerator.
6675 *
6676 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
6677 */
6678
6679static VALUE
6680rb_str_gsub(int argc, VALUE *argv, VALUE str)
6681{
6682 return str_gsub(argc, argv, str, 0);
6683}
6684
6685
6686/*
6687 * call-seq:
6688 * replace(other_string) -> self
6689 *
6690 * Replaces the contents of +self+ with the contents of +other_string+;
6691 * returns +self+:
6692 *
6693 * s = 'foo' # => "foo"
6694 * s.replace('bar') # => "bar"
6695 *
6696 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6697 */
6698
6699VALUE
6701{
6702 str_modifiable(str);
6703 if (str == str2) return str;
6704
6705 StringValue(str2);
6706 str_discard(str);
6707 return str_replace(str, str2);
6708}
6709
6710/*
6711 * call-seq:
6712 * clear -> self
6713 *
6714 * Removes the contents of +self+:
6715 *
6716 * s = 'foo'
6717 * s.clear # => ""
6718 * s # => ""
6719 *
6720 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6721 */
6722
6723static VALUE
6724rb_str_clear(VALUE str)
6725{
6726 str_discard(str);
6727 STR_SET_EMBED(str);
6728 STR_SET_LEN(str, 0);
6729 RSTRING_PTR(str)[0] = 0;
6730 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6732 else
6734 return str;
6735}
6736
6737/*
6738 * call-seq:
6739 * chr -> string
6740 *
6741 * :include: doc/string/chr.rdoc
6742 *
6743 */
6744
6745static VALUE
6746rb_str_chr(VALUE str)
6747{
6748 return rb_str_substr(str, 0, 1);
6749}
6750
6751/*
6752 * call-seq:
6753 * getbyte(index) -> integer or nil
6754 *
6755 * :include: doc/string/getbyte.rdoc
6756 *
6757 */
6758VALUE
6759rb_str_getbyte(VALUE str, VALUE index)
6760{
6761 rb_len_t pos = NUM2LEN(index);
6762
6763 if (pos < 0)
6764 pos += RSTRING_LEN(str);
6765 if (pos < 0 || RSTRING_LEN(str) <= pos)
6766 return Qnil;
6767
6768 return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
6769}
6770
6771/*
6772 * call-seq:
6773 * setbyte(index, integer) -> integer
6774 *
6775 * Sets the byte at zero-based offset +index+ to the value of the given +integer+;
6776 * returns +integer+:
6777 *
6778 * s = 'xyzzy'
6779 * s.setbyte(2, 129) # => 129
6780 * s # => "xy\x81zy"
6781 *
6782 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6783 */
6784VALUE
6785rb_str_setbyte(VALUE str, VALUE index, VALUE value)
6786{
6787 rb_len_t pos = NUM2LEN(index);
6788 char *ptr, *head, *left = 0;
6789 rb_encoding *enc;
6790 int cr = ENC_CODERANGE_UNKNOWN, width, nlen;
6791
6792 VALUE v = rb_to_int(value);
6793 VALUE w = rb_int_and(v, INT2FIX(0xff));
6794 char byte = (char)(NUM2INT(w) & 0xFF);
6795
6796 rb_len_t len = RSTRING_LEN(str);
6797 if (pos < -len || len <= pos)
6798 rb_raise(rb_eIndexError, "index %"PRIdLEN" out of string", pos);
6799 if (pos < 0)
6800 pos += len;
6801
6802 if (!str_independent(str))
6803 str_make_independent(str);
6804 enc = STR_ENC_GET(str);
6805 head = RSTRING_PTR(str);
6806 ptr = &head[pos];
6807 if (!STR_EMBED_P(str)) {
6808 cr = ENC_CODERANGE(str);
6809 switch (cr) {
6810 case ENC_CODERANGE_7BIT:
6811 left = ptr;
6812 *ptr = byte;
6813 if (ISASCII(byte)) goto end;
6814 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6815 if (!MBCLEN_CHARFOUND_P(nlen))
6817 else
6819 goto end;
6821 left = rb_enc_left_char_head(head, ptr, head+len, enc);
6822 width = rb_enc_precise_mbclen(left, head+len, enc);
6823 *ptr = byte;
6824 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6825 if (!MBCLEN_CHARFOUND_P(nlen))
6827 else if (MBCLEN_CHARFOUND_LEN(nlen) != width || ISASCII(byte))
6829 goto end;
6830 }
6831 }
6833 *ptr = byte;
6834
6835 end:
6836 return value;
6837}
6838
6839static inline bool
6840str_bit_offset_out_of_range(rb_len_t byte_len, uint64_t bit_offset)
6841{
6842 /* Compare byte indexes to avoid overflowing byte_len * CHAR_BIT. */
6843 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6844}
6845
6846/*
6847 * Keep both the full bit offset and its rb_len_t representation. Most calls
6848 * use a Fixnum-sized offset and can stay on the rb_len_t fast path; only large
6849 * Bignum offsets need the uint64_t path below. This matters on platforms where
6850 * rb_len_t is 32 bits.
6851 */
6853 uint64_t value;
6854 rb_len_t index_value;
6855 bool fits_index;
6856};
6857
6858static inline struct str_bit_offset
6859str_bit_offset_from_index(VALUE index)
6860{
6861 VALUE integer = rb_to_int(index);
6862 struct str_bit_offset offset;
6863
6864 /*
6865 * FIXNUM_P only decides whether the common rb_len_t path is immediately
6866 * usable. This covers practically all offsets on LP64 platforms; Bignum
6867 * offsets are still accepted below when they fit in uint64_t, mainly for
6868 * platforms with 32-bit rb_len_t where large strings can have Bignum bit
6869 * offsets.
6870 */
6871 if (FIXNUM_P(integer)) {
6872 offset.index_value = FIX2LONG(integer);
6873 if (offset.index_value < 0) {
6874 rb_raise(rb_eIndexError, "bit index out of range");
6875 }
6876 offset.value = (uint64_t)offset.index_value;
6877 offset.fits_index = true;
6878 return offset;
6879 }
6880
6881 RUBY_ASSERT(RB_TYPE_P(integer, T_BIGNUM));
6882 if (rb_int_negative_p(integer)) {
6883 rb_raise(rb_eIndexError, "bit index out of range");
6884 }
6885 if (rb_cmpint(rb_int_cmp(integer, ULL2NUM(UINT64_MAX)), integer, ULL2NUM(UINT64_MAX)) > 0) {
6886 rb_raise(rb_eArgError, "bit index out of representable range");
6887 }
6888
6889 offset.value = (uint64_t)NUM2ULL(integer);
6890 if (offset.value <= (uint64_t)RB_LEN_MAX) {
6891 offset.index_value = (rb_len_t)offset.value;
6892 offset.fits_index = true;
6893 }
6894 else {
6895 offset.index_value = 0;
6896 offset.fits_index = false;
6897 }
6898 return offset;
6899}
6900
6901/*
6902 * Bit lengths share the offset's representable range.
6903 * A negative length is an ArgumentError rather than an IndexError.
6904 */
6905static uint64_t
6906str_bit_length_from_index(VALUE index)
6907{
6908 VALUE integer = rb_to_int(index);
6909
6910 if (FIXNUM_P(integer)) {
6911 rb_len_t value = FIX2LONG(integer);
6912 if (value < 0) {
6913 rb_raise(rb_eArgError, "negative bit length");
6914 }
6915 return (uint64_t)value;
6916 }
6917
6918 RUBY_ASSERT(RB_TYPE_P(integer, T_BIGNUM));
6919 if (rb_int_negative_p(integer)) {
6920 rb_raise(rb_eArgError, "negative bit length");
6921 }
6922 if (rb_cmpint(rb_int_cmp(integer, ULL2NUM(UINT64_MAX)), integer, ULL2NUM(UINT64_MAX)) > 0) {
6923 rb_raise(rb_eArgError, "bit length out of representable range");
6924 }
6925 return (uint64_t)NUM2ULL(integer);
6926}
6927
6928static inline uint64_t
6929str_bit_size(rb_len_t byte_len)
6930{
6931 /*
6932 * byte_len * CHAR_BIT overflows uint64_t only for byte_len >= 2**61 which cannot
6933 * be allocated. Saturate so that unreachable cases cannot wrap.
6934 */
6935 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT) return UINT64_MAX;
6936 return (uint64_t)byte_len * CHAR_BIT;
6937}
6938
6940 uint64_t beg;
6941 uint64_t end_exclusive; /* meaningful only when end_open is false */
6942 bool end_open; /* a nil end: the region runs to the end of self */
6943};
6944
6945/*
6946 * Coerce a bit Range's endpoints to bit offsets. This may run arbitrary Ruby
6947 * (Integer#to_int on the endpoints), so it does NOT read the string's length:
6948 * The caller must resolve the length only after this returns, otherwise
6949 * to_int that reallocates self would leave a stale size.
6950 */
6951static void
6952str_bit_range_to_offsets(VALUE range, struct str_bit_range *out)
6953{
6954 VALUE beg_v, end_v;
6955 int excl;
6956
6957 /*
6958 * We don't use rb_range_beg_len: it counts negative endpoints from the end,
6959 * which is an IndexError for bit positions, and it is limited to long instead
6960 * of uint64_t.
6961 */
6962 rb_range_values(range, &beg_v, &end_v, &excl);
6963
6964 out->beg = NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6965 if (NIL_P(end_v)) {
6966 out->end_open = true;
6967 out->end_exclusive = 0;
6968 }
6969 else {
6970 uint64_t end = str_bit_offset_from_index(end_v).value;
6971 out->end_open = false;
6972 /*
6973 * The saturation loses one position only for an inclusive end of
6974 * 2**64-1, which lies beyond any real string either way.
6975 */
6976 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6977 }
6978}
6979
6980/*
6981 * Turn a coerced Range into (beg, len) against the now-current total bit size.
6982 * The length is deliberately not clamped to the bits available, so a reading
6983 * caller can clamp while a writing caller detects the overrun and raises.
6984 */
6985static bool
6986str_bit_range_resolve(const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6987{
6988 uint64_t beg = range->beg;
6989 if (beg > total_bits) return false;
6990
6991 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6992 if (end_exclusive < beg) end_exclusive = beg;
6993
6994 *begp = beg;
6995 *lenp = end_exclusive - beg;
6996 return true;
6997}
6998
6999static bool
7000str_lsb_first_from_opts(VALUE opts)
7001{
7002 static ID keywords[1];
7003 VALUE vlsb_first;
7004
7005 if (!keywords[0]) {
7006 keywords[0] = rb_intern_const("lsb_first");
7007 }
7008
7009 rb_get_kwargs(opts, keywords, 0, 1, &vlsb_first);
7010 if (vlsb_first == Qundef || vlsb_first == Qtrue) {
7011 return true;
7012 }
7013 if (vlsb_first == Qfalse) {
7014 return false;
7015 }
7016 rb_raise(rb_eArgError, "lsb_first must be true or false");
7017 UNREACHABLE_RETURN(false);
7018}
7019
7020static bool
7021str_lsb_first(int argc, VALUE *argv, VALUE *index)
7022{
7023 VALUE opts;
7024
7025 rb_scan_args(argc, argv, "1:", index, &opts);
7026 return str_lsb_first_from_opts(opts);
7027}
7028
7029static inline uint64_t
7030str_logical_to_physical_bit64(uint64_t logical, bool lsb_first)
7031{
7032 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
7033}
7034
7035static inline rb_len_t
7036str_logical_to_physical_bit(rb_len_t logical, bool lsb_first)
7037{
7038 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
7039}
7040
7042 rb_len_t byte_index;
7043 unsigned int bit_offset;
7044};
7045
7046static inline struct str_bit_location
7047str_bit_location_from_offset(uint64_t logical, bool lsb_first)
7048{
7049 /*
7050 * When rb_len_t is 32-bit, a bit offset for a large string can be a Bignum
7051 * while the byte index still fits in rb_len_t, which is RSTRING_LEN's type.
7052 */
7053 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7054 struct str_bit_location location;
7055 location.byte_index = (rb_len_t)(physical / CHAR_BIT);
7056 location.bit_offset = (unsigned int)(physical % CHAR_BIT);
7057 return location;
7058}
7059
7060static inline int
7061str_get_bit(const char *ptr, rb_len_t bit_index)
7062{
7063 return (((unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7064}
7065
7066static inline int
7067str_get_bit_location(const char *ptr, struct str_bit_location location)
7068{
7069 return (((unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7070}
7071
7072static int
7073str_bit_get(int argc, VALUE *argv, VALUE str)
7074{
7075 VALUE index;
7076 bool lsb_first = str_lsb_first(argc, argv, &index);
7077 struct str_bit_offset offset = str_bit_offset_from_index(index);
7078
7079 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7080 return -1;
7081 }
7082
7083 if (offset.fits_index) {
7084 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.index_value, lsb_first));
7085 }
7086 else {
7087 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7088 }
7089}
7090
7091/*
7092 * call-seq:
7093 * bit_get(offset, lsb_first: true) -> 0, 1, or nil
7094 *
7095 * :include: doc/string/bit_get.rdoc
7096 *
7097 */
7098static VALUE
7099rb_str_bit_get(int argc, VALUE *argv, VALUE str)
7100{
7101 int bit = str_bit_get(argc, argv, str);
7102 return bit < 0 ? Qnil : INT2FIX(bit);
7103}
7104
7105/*
7106 * call-seq:
7107 * bit_set?(offset, lsb_first: true) -> true, false, or nil
7108 *
7109 * :include: doc/string/bit_set_p.rdoc
7110 *
7111 */
7112static VALUE
7113rb_str_bit_set_p(int argc, VALUE *argv, VALUE str)
7114{
7115 int bit = str_bit_get(argc, argv, str);
7116 return bit < 0 ? Qnil : RBOOL(bit);
7117}
7118
7119enum str_bit_mutation {
7120 STR_BIT_SET,
7121 STR_BIT_CLEAR,
7122 STR_BIT_FLIP
7123};
7124
7125/*
7126 * Mask for the logical in-byte positions lo..hi (0 <= lo <= hi <= 7) of one
7127 * byte. A contiguous logical run stays contiguous within a byte under both
7128 * numbering conventions; MSB-first only mirrors it.
7129 */
7130static inline unsigned char
7131str_bit_region_byte_mask(unsigned int lo, unsigned int hi, bool lsb_first)
7132{
7133 if (lsb_first) {
7134 return (unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7135 }
7136 else {
7137 return (unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7138 }
7139}
7140
7141static inline void
7142str_apply_bit_mask(unsigned char *byte, unsigned char mask, enum str_bit_mutation mutation)
7143{
7144 switch (mutation) {
7145 case STR_BIT_SET:
7146 *byte |= mask;
7147 break;
7148 case STR_BIT_CLEAR:
7149 *byte &= (unsigned char)~mask;
7150 break;
7151 case STR_BIT_FLIP:
7152 *byte ^= mask;
7153 break;
7154 }
7155}
7156
7157/* The caller has bounds-checked [beg, beg+len) and called rb_str_modify. */
7158static void
7159str_mutate_bit_region(unsigned char *ptr, uint64_t beg, uint64_t len, bool lsb_first, enum str_bit_mutation mutation)
7160{
7161 uint64_t first_bit = beg;
7162 uint64_t last_bit = beg + len - 1;
7163 rb_len_t first_byte = (rb_len_t)(first_bit / CHAR_BIT);
7164 rb_len_t last_byte = (rb_len_t)(last_bit / CHAR_BIT);
7165 unsigned int first_off = (unsigned int)(first_bit % CHAR_BIT);
7166 unsigned int last_off = (unsigned int)(last_bit % CHAR_BIT);
7167
7168 if (first_byte == last_byte) {
7169 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7170 return;
7171 }
7172
7173 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7174 rb_len_t middle_len = last_byte - first_byte - 1;
7175 if (middle_len > 0) {
7176 unsigned char *middle = ptr + first_byte + 1;
7177 switch (mutation) {
7178 case STR_BIT_SET:
7179 memset(middle, 0xFF, middle_len);
7180 break;
7181 case STR_BIT_CLEAR:
7182 memset(middle, 0, middle_len);
7183 break;
7184 case STR_BIT_FLIP:
7185 /*
7186 * Byte loop on purpose: the compiler auto-vectorizes it (verified on gcc 13.3
7187 * and clang 18.1 with x86_64), and being read-modify-write, the flip is memory-bound,
7188 * so a manual word-at-a-time XOR loop was measured to be no faster.
7189 */
7190 for (rb_len_t i = 0; i < middle_len; i++) {
7191 middle[i] ^= 0xFF;
7192 }
7193 break;
7194 }
7195 }
7196 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7197}
7198
7199static VALUE
7200str_mutate_single_bit(VALUE str, VALUE index, bool lsb_first, enum str_bit_mutation mutation)
7201{
7202 struct str_bit_offset offset = str_bit_offset_from_index(index);
7203 struct str_bit_location location;
7204 rb_len_t bit_index;
7205 unsigned char *ptr;
7206 unsigned char mask;
7207
7208 rb_check_frozen(str);
7209
7210 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7211 rb_raise(rb_eIndexError, "bit index out of range");
7212 }
7213
7214 rb_str_modify(str);
7215 ptr = (unsigned char *)RSTRING_PTR(str);
7216 if (offset.fits_index) {
7217 bit_index = str_logical_to_physical_bit(offset.index_value, lsb_first);
7218 mask = (unsigned char)(1u << (bit_index % CHAR_BIT));
7219 location.byte_index = bit_index / CHAR_BIT;
7220 }
7221 else {
7222 location = str_bit_location_from_offset(offset.value, lsb_first);
7223 mask = (unsigned char)(1u << location.bit_offset);
7224 }
7225
7226 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7227 return str;
7228}
7229
7230static VALUE
7231str_mutate_bit(int argc, VALUE *argv, VALUE str, enum str_bit_mutation mutation)
7232{
7233 VALUE target, length_v, opts;
7234 uint64_t beg = 0, len = 0;
7235
7236 /* Count positional arguments so that an explicit nil is not mistaken for an omitted one. */
7237 int nargs = rb_scan_args(argc, argv, "11:", &target, &length_v, &opts);
7238 bool lsb_first = str_lsb_first_from_opts(opts);
7239
7240 bool is_range = rb_obj_is_kind_of(target, rb_cRange);
7241 if (nargs == 1 && !is_range) {
7242 return str_mutate_single_bit(str, target, lsb_first, mutation);
7243 }
7244
7245 struct str_bit_range range = {0};
7246 struct str_bit_offset offset;
7247 if (is_range) {
7248 if (nargs == 2) {
7249 rb_raise(rb_eArgError, "bit length not allowed with a Range");
7250 }
7251 str_bit_range_to_offsets(target, &range);
7252 }
7253 else {
7254 offset = str_bit_offset_from_index(target);
7255 len = str_bit_length_from_index(length_v);
7256 }
7257
7258 /* Even a zero-length write requires a mutable receiver. */
7259 rb_check_frozen(str);
7260
7261 /*
7262 * A region that begins past the end is out of range even when it is
7263 * empty, and one that runs past the end is not allowed to silently
7264 * shrink: both are errors for a mutation, unlike the clamping reads.
7265 * An empty region whose start is within 0..bitsize writes nothing.
7266 */
7267 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7268 if (is_range) {
7269 if (!str_bit_range_resolve(&range, total_bits, &beg, &len) || len > total_bits - beg) {
7270 rb_raise(rb_eIndexError, "bit range out of range");
7271 }
7272 }
7273 else {
7274 beg = offset.value;
7275 if (beg > total_bits || len > total_bits - beg) {
7276 rb_raise(rb_eIndexError, "bit range out of range");
7277 }
7278 }
7279
7280 if (len == 0) return str;
7281
7282 rb_str_modify(str);
7283 str_mutate_bit_region((unsigned char *)RSTRING_PTR(str), beg, len, lsb_first, mutation);
7284 return str;
7285}
7286
7287/*
7288 * call-seq:
7289 * bit_set(offset, lsb_first: true) -> self
7290 * bit_set(offset, length, lsb_first: true) -> self
7291 * bit_set(range, lsb_first: true) -> self
7292 *
7293 * :include: doc/string/bit_set.rdoc
7294 *
7295 */
7296static VALUE
7297rb_str_bit_set(int argc, VALUE *argv, VALUE str)
7298{
7299 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7300}
7301
7302/*
7303 * call-seq:
7304 * bit_clear(offset, lsb_first: true) -> self
7305 * bit_clear(offset, length, lsb_first: true) -> self
7306 * bit_clear(range, lsb_first: true) -> self
7307 *
7308 * :include: doc/string/bit_clear.rdoc
7309 *
7310 */
7311static VALUE
7312rb_str_bit_clear(int argc, VALUE *argv, VALUE str)
7313{
7314 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7315}
7316
7317/*
7318 * call-seq:
7319 * bit_flip(offset, lsb_first: true) -> self
7320 * bit_flip(offset, length, lsb_first: true) -> self
7321 * bit_flip(range, lsb_first: true) -> self
7322 *
7323 * :include: doc/string/bit_flip.rdoc
7324 *
7325 */
7326static VALUE
7327rb_str_bit_flip(int argc, VALUE *argv, VALUE str)
7328{
7329 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7330}
7331
7332static uint64_t
7333str_count_bits(const unsigned char *ptr, rb_len_t len)
7334{
7335 uint64_t count = 0;
7336 rb_len_t off = 0;
7337 rb_len_t unrolled_end = len & ~31L;
7338 rb_len_t aligned_end = len & ~7L;
7339
7340 // 32 bytes (256 bits) at a time
7341 for (; off < unrolled_end; off += 32) {
7342 uint64_t w0, w1, w2, w3;
7343 memcpy(&w0, ptr + off, 8);
7344 memcpy(&w1, ptr + off + 8, 8);
7345 memcpy(&w2, ptr + off + 16, 8);
7346 memcpy(&w3, ptr + off + 24, 8);
7347 count += rb_popcount64(w0);
7348 count += rb_popcount64(w1);
7349 count += rb_popcount64(w2);
7350 count += rb_popcount64(w3);
7351 }
7352
7353 // 8 bytes (64 bits) at a time
7354 for (; off < aligned_end; off += 8) {
7355 uint64_t word;
7356 memcpy(&word, ptr + off, 8);
7357 count += rb_popcount64(word);
7358 }
7359
7360 // remaining bytes
7361 if (off < len) {
7362 uint64_t word = 0;
7363 int shift = 0;
7364 for (; off < len; off++, shift += CHAR_BIT) {
7365 word |= (uint64_t)ptr[off] << shift;
7366 }
7367 count += rb_popcount64(word);
7368 }
7369
7370 return count;
7371}
7372
7373static uint64_t
7374str_count_bits_region(const unsigned char *ptr, uint64_t beg, uint64_t len, bool lsb_first)
7375{
7376 uint64_t first_bit = beg;
7377 uint64_t last_bit = beg + len - 1;
7378 rb_len_t first_byte = (rb_len_t)(first_bit / CHAR_BIT);
7379 rb_len_t last_byte = (rb_len_t)(last_bit / CHAR_BIT);
7380 unsigned int first_off = (unsigned int)(first_bit % CHAR_BIT);
7381 unsigned int last_off = (unsigned int)(last_bit % CHAR_BIT);
7382
7383 if (first_byte == last_byte) {
7384 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7385 }
7386
7387 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7388 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7389 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7390 return count;
7391}
7392
7393/*
7394 * call-seq:
7395 * bit_count -> integer
7396 * bit_count(offset, length, lsb_first: true) -> integer
7397 * bit_count(range, lsb_first: true) -> integer
7398 *
7399 * :include: doc/string/bit_count.rdoc
7400 *
7401 */
7402static VALUE
7403rb_str_bit_count(int argc, VALUE *argv, VALUE str)
7404{
7405 VALUE v0, v1, opts;
7406 uint64_t beg = 0, len = 0;
7407
7408 /* Count positional arguments so that an explicit nil is not mistaken for an omitted one. */
7409 int nargs = rb_scan_args(argc, argv, "02:", &v0, &v1, &opts);
7410 /*
7411 * A whole-string popcount is independent of bit numbering.
7412 * no-(offset|range)-argument form only validates lsb_first.
7413 */
7414 bool lsb_first = str_lsb_first_from_opts(opts);
7415
7416 if (nargs == 0) {
7417 return ULL2NUM(str_count_bits((const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7418 }
7419
7420 bool is_range = rb_obj_is_kind_of(v0, rb_cRange);
7421 struct str_bit_range range = {0};
7422 if (is_range) {
7423 if (nargs == 2) {
7424 rb_raise(rb_eArgError, "bit length not allowed with a Range");
7425 }
7426 str_bit_range_to_offsets(v0, &range);
7427 }
7428 else if (nargs == 1) {
7429 rb_raise(rb_eArgError, "no bit length given");
7430 }
7431 else {
7432 beg = str_bit_offset_from_index(v0).value;
7433 len = str_bit_length_from_index(v1);
7434 }
7435
7436 const unsigned char *ptr = (const unsigned char *)RSTRING_PTR(str);
7437 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7438 if (is_range) {
7439 if (!str_bit_range_resolve(&range, total_bits, &beg, &len)) {
7440 return INT2FIX(0);
7441 }
7442 }
7443 else if (beg >= total_bits) {
7444 return INT2FIX(0);
7445 }
7446
7447 /* Reads clamp: only the part of the region that exists is counted. */
7448 if (len > total_bits - beg) len = total_bits - beg;
7449 if (len == 0) return INT2FIX(0);
7450 return ULL2NUM(str_count_bits_region(ptr, beg, len, lsb_first));
7451}
7452
7453static void
7454str_check_bitwise_length(VALUE str, VALUE other)
7455{
7456 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7457 rb_raise(rb_eArgError, "operands must have the same length (%"PRIdLEN" vs %"PRIdLEN")",
7458 RSTRING_LEN(str), RSTRING_LEN(other));
7459 }
7460}
7461
7462static VALUE
7463str_bitwise_result(VALUE str)
7464{
7465 rb_len_t len = RSTRING_LEN(str);
7466 VALUE result = rb_str_buf_new(len);
7467 rb_str_resize(result, len);
7468 rb_enc_associate(result, rb_ascii8bit_encoding());
7469 ENC_CODERANGE_CLEAR(result);
7470 return result;
7471}
7472
7473#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7474 static void \
7475 name(unsigned char *dst, const unsigned char *src, rb_len_t len) \
7476 { \
7477 rb_len_t off = 0; \
7478 rb_len_t unrolled_end = len & ~31L; \
7479 rb_len_t aligned_end = len & ~7L; \
7480 for (; off < unrolled_end; off += 32) { \
7481 uint64_t s0, s1, s2, s3; \
7482 memcpy(&s0, src + off, 8); \
7483 memcpy(&s1, src + off + 8, 8); \
7484 memcpy(&s2, src + off + 16, 8); \
7485 memcpy(&s3, src + off + 24, 8); \
7486 s0 = (expr_word(s0)); \
7487 s1 = (expr_word(s1)); \
7488 s2 = (expr_word(s2)); \
7489 s3 = (expr_word(s3)); \
7490 memcpy(dst + off, &s0, 8); \
7491 memcpy(dst + off + 8, &s1, 8); \
7492 memcpy(dst + off + 16, &s2, 8); \
7493 memcpy(dst + off + 24, &s3, 8); \
7494 } \
7495 for (; off < aligned_end; off += 8) { \
7496 uint64_t word; \
7497 memcpy(&word, src + off, 8); \
7498 word = (expr_word(word)); \
7499 memcpy(dst + off, &word, 8); \
7500 } \
7501 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7502 }
7503
7504#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7505 static void \
7506 name(unsigned char *dst, const unsigned char *lhs, \
7507 const unsigned char *rhs, rb_len_t len) \
7508 { \
7509 rb_len_t off = 0; \
7510 rb_len_t unrolled_end = len & ~31L; \
7511 rb_len_t aligned_end = len & ~7L; \
7512 for (; off < unrolled_end; off += 32) { \
7513 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7514 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7515 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7516 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7517 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7518 l0 = expr_word(l0, r0); \
7519 l1 = expr_word(l1, r1); \
7520 l2 = expr_word(l2, r2); \
7521 l3 = expr_word(l3, r3); \
7522 memcpy(dst + off, &l0, 8); \
7523 memcpy(dst + off + 8, &l1, 8); \
7524 memcpy(dst + off + 16, &l2, 8); \
7525 memcpy(dst + off + 24, &l3, 8); \
7526 } \
7527 for (; off < aligned_end; off += 8) { \
7528 uint64_t lhs_word, rhs_word; \
7529 memcpy(&lhs_word, lhs + off, 8); \
7530 memcpy(&rhs_word, rhs + off, 8); \
7531 lhs_word = expr_word(lhs_word, rhs_word); \
7532 memcpy(dst + off, &lhs_word, 8); \
7533 } \
7534 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7535 }
7536
7537#define STR_BITWISE_NOT_WORD(x) (~(x))
7538#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7539#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7540#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7541#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7542#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7543#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7544#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7545
7546STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7547STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7548STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7549STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7550
7551/*
7552 * call-seq:
7553 * bitwise_not -> string
7554 *
7555 * :include: doc/string/bitwise_not.rdoc
7556 *
7557 */
7558static VALUE
7559rb_str_bitwise_not(VALUE str)
7560{
7561 rb_len_t len = RSTRING_LEN(str);
7562 VALUE result = str_bitwise_result(str);
7563 str_bitwise_not((unsigned char *)RSTRING_PTR(result),
7564 (const unsigned char *)RSTRING_PTR(str), len);
7565 return result;
7566}
7567
7568/*
7569 * call-seq:
7570 * bitwise_not! -> self
7571 *
7572 * :include: doc/string/bitwise_not_bang.rdoc
7573 *
7574 */
7575static VALUE
7576rb_str_bitwise_not_bang(VALUE str)
7577{
7578 rb_len_t len;
7579 unsigned char *ptr;
7580
7581 rb_str_modify(str);
7582 len = RSTRING_LEN(str);
7583 ptr = (unsigned char *)RSTRING_PTR(str);
7584 str_bitwise_not(ptr, ptr, len);
7585 return str;
7586}
7587
7588/*
7589 * Document-method: String#bitwise_and
7590 *
7591 * call-seq:
7592 * bitwise_and -> new_string
7593 *
7594 * :include: doc/string/bitwise_and.rdoc
7595 *
7596 */
7597
7598/*
7599 * Document-method: String#bitwise_and!
7600 *
7601 * call-seq:
7602 * bitwise_and! -> self
7603 *
7604 * :include: doc/string/bitwise_and_bang.rdoc
7605 *
7606 */
7607
7608/*
7609 * Document-method: String#bitwise_or
7610 *
7611 * call-seq:
7612 * bitwise_or -> new_string
7613 *
7614 * :include: doc/string/bitwise_or.rdoc
7615 *
7616 */
7617
7618/*
7619 * Document-method: String#bitwise_or!
7620 *
7621 * call-seq:
7622 * bitwise_or! -> self
7623 *
7624 * :include: doc/string/bitwise_or_bang.rdoc
7625 *
7626 */
7627
7628/*
7629 * Document-method: String#bitwise_xor
7630 *
7631 * call-seq:
7632 * bitwise_xor -> new_string
7633 *
7634 * :include: doc/string/bitwise_xor.rdoc
7635 *
7636 */
7637
7638/*
7639 * Document-method: String#bitwise_xor!
7640 *
7641 * call-seq:
7642 * bitwise_xor! -> self
7643 *
7644 * :include: doc/string/bitwise_xor_bang.rdoc
7645 *
7646 */
7647
7648#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7649 static VALUE \
7650 rb_str_bitwise_##name(VALUE str, VALUE other) \
7651 { \
7652 rb_len_t len; \
7653 VALUE result; \
7654 StringValue(other); \
7655 str_check_bitwise_length(str, other); \
7656 len = RSTRING_LEN(str); \
7657 result = str_bitwise_result(str); \
7658 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7659 (const unsigned char *)RSTRING_PTR(str), \
7660 (const unsigned char *)RSTRING_PTR(other), len); \
7661 return result; \
7662 } \
7663 static VALUE \
7664 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7665 { \
7666 rb_len_t len; \
7667 unsigned char *ptr; \
7668 StringValue(other); \
7669 str_check_bitwise_length(str, other); \
7670 rb_str_modify(str); \
7671 len = RSTRING_LEN(str); \
7672 ptr = (unsigned char *)RSTRING_PTR(str); \
7673 str_bitwise_##name(ptr, ptr, \
7674 (const unsigned char *)RSTRING_PTR(other), len); \
7675 return str; \
7676 }
7677
7678STR_DEFINE_BINARY_BITWISE_METHOD(and)
7679STR_DEFINE_BINARY_BITWISE_METHOD(or)
7680STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7681
7682static VALUE
7683str_byte_substr(VALUE str, rb_len_t beg, rb_len_t len, int empty)
7684{
7685 rb_len_t n = RSTRING_LEN(str);
7686
7687 if (beg > n || len < 0) return Qnil;
7688 if (beg < 0) {
7689 beg += n;
7690 if (beg < 0) return Qnil;
7691 }
7692 if (len > n - beg)
7693 len = n - beg;
7694 if (len <= 0) {
7695 if (!empty) return Qnil;
7696 len = 0;
7697 }
7698
7699 VALUE str2 = str_subseq(str, beg, len);
7700
7701 str_enc_copy_direct(str2, str);
7702
7703 if (RSTRING_LEN(str2) == 0) {
7704 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7706 else
7708 }
7709 else {
7710 switch (ENC_CODERANGE(str)) {
7711 case ENC_CODERANGE_7BIT:
7713 break;
7714 default:
7716 break;
7717 }
7718 }
7719
7720 return str2;
7721}
7722
7723VALUE
7724rb_str_byte_substr(VALUE str, VALUE beg, VALUE len)
7725{
7726 return str_byte_substr(str, NUM2LEN(beg), NUM2LEN(len), TRUE);
7727}
7728
7729static VALUE
7730str_byte_aref(VALUE str, VALUE indx)
7731{
7732 rb_len_t idx;
7733 if (FIXNUM_P(indx)) {
7734 idx = FIX2LONG(indx);
7735 }
7736 else {
7737 /* check if indx is Range */
7738 rb_len_t beg, len = RSTRING_LEN(str);
7739
7740 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
7741 case Qfalse:
7742 break;
7743 case Qnil:
7744 return Qnil;
7745 default:
7746 return str_byte_substr(str, beg, len, TRUE);
7747 }
7748
7749 idx = NUM2LEN(indx);
7750 }
7751 return str_byte_substr(str, idx, 1, FALSE);
7752}
7753
7754/*
7755 * call-seq:
7756 * byteslice(offset, length = 1) -> string or nil
7757 * byteslice(range) -> string or nil
7758 *
7759 * :include: doc/string/byteslice.rdoc
7760 */
7761
7762static VALUE
7763rb_str_byteslice(int argc, VALUE *argv, VALUE str)
7764{
7765 if (argc == 2) {
7766 rb_len_t beg = NUM2LEN(argv[0]);
7767 rb_len_t len = NUM2LEN(argv[1]);
7768 return str_byte_substr(str, beg, len, TRUE);
7769 }
7770 rb_check_arity(argc, 1, 2);
7771 return str_byte_aref(str, argv[0]);
7772}
7773
7774static void
7775str_check_beg_len(VALUE str, rb_len_t *beg, rb_len_t *len)
7776{
7777 rb_len_t end, slen = RSTRING_LEN(str);
7778
7779 if (*len < 0) rb_raise(rb_eIndexError, "negative length %"PRIdLEN, *len);
7780 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7781 rb_raise(rb_eIndexError, "index %"PRIdLEN" out of string", *beg);
7782 }
7783 if (*beg < 0) {
7784 *beg += slen;
7785 }
7786 RUBY_ASSERT(*beg >= 0);
7787 RUBY_ASSERT(*beg <= slen);
7788
7789 if (*len > slen - *beg) {
7790 *len = slen - *beg;
7791 }
7792 end = *beg + *len;
7793 str_ensure_byte_pos(str, *beg);
7794 str_ensure_byte_pos(str, end);
7795}
7796
7797/*
7798 * call-seq:
7799 * bytesplice(offset, length, str) -> self
7800 * bytesplice(offset, length, str, str_offset, str_length) -> self
7801 * bytesplice(range, str) -> self
7802 * bytesplice(range, str, str_range) -> self
7803 *
7804 * :include: doc/string/bytesplice.rdoc
7805 */
7806
7807static VALUE
7808rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
7809{
7810 rb_len_t beg, len, vbeg, vlen;
7811 VALUE val;
7812 int cr;
7813
7814 rb_check_arity(argc, 2, 5);
7815 if (!(argc == 2 || argc == 3 || argc == 5)) {
7816 rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7817 }
7818 if (argc == 2 || (argc == 3 && !RB_INTEGER_TYPE_P(argv[0]))) {
7819 if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
7820 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7821 rb_builtin_class_name(argv[0]));
7822 }
7823 val = argv[1];
7824 StringValue(val);
7825 if (argc == 2) {
7826 /* bytesplice(range, str) */
7827 vbeg = 0;
7828 vlen = RSTRING_LEN(val);
7829 }
7830 else {
7831 /* bytesplice(range, str, str_range) */
7832 if (!rb_range_beg_len(argv[2], &vbeg, &vlen, RSTRING_LEN(val), 2)) {
7833 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
7834 rb_builtin_class_name(argv[2]));
7835 }
7836 }
7837 }
7838 else {
7839 beg = NUM2LEN(argv[0]);
7840 len = NUM2LEN(argv[1]);
7841 val = argv[2];
7842 StringValue(val);
7843 if (argc == 3) {
7844 /* bytesplice(index, length, str) */
7845 vbeg = 0;
7846 vlen = RSTRING_LEN(val);
7847 }
7848 else {
7849 /* bytesplice(index, length, str, str_index, str_length) */
7850 vbeg = NUM2LEN(argv[3]);
7851 vlen = NUM2LEN(argv[4]);
7852 }
7853 }
7854 str_check_beg_len(str, &beg, &len);
7855 str_check_beg_len(val, &vbeg, &vlen);
7856 str_modify_keep_cr(str);
7857
7858 if (RB_UNLIKELY(ENCODING_GET_INLINED(str) != ENCODING_GET_INLINED(val))) {
7859 rb_enc_associate(str, rb_enc_check(str, val));
7860 }
7861
7862 rb_str_update_1(str, beg, len, val, vbeg, vlen);
7864 if (cr != ENC_CODERANGE_BROKEN)
7865 ENC_CODERANGE_SET(str, cr);
7866 return str;
7867}
7868
7869/*
7870 * call-seq:
7871 * reverse -> new_string
7872 *
7873 * Returns a new string with the characters from +self+ in reverse order.
7874 *
7875 * 'drawer'.reverse # => "reward"
7876 * 'reviled'.reverse # => "deliver"
7877 * 'stressed'.reverse # => "desserts"
7878 * 'semordnilaps'.reverse # => "spalindromes"
7879 *
7880 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7881 */
7882
7883static VALUE
7884rb_str_reverse(VALUE str)
7885{
7886 rb_encoding *enc;
7887 VALUE rev;
7888 char *s, *e, *p;
7889 int cr;
7890
7891 if (RSTRING_LEN(str) <= 1) return str_duplicate(rb_cString, str);
7892 enc = STR_ENC_GET(str);
7893 rev = rb_str_new(0, RSTRING_LEN(str));
7894 s = RSTRING_PTR(str); e = RSTRING_END(str);
7895 p = RSTRING_END(rev);
7896 cr = ENC_CODERANGE(str);
7897
7898 if (RSTRING_LEN(str) > 1) {
7899 if (single_byte_optimizable(str)) {
7900 while (s < e) {
7901 *--p = *s++;
7902 }
7903 }
7904 else if (cr == ENC_CODERANGE_VALID) {
7905 while (s < e) {
7906 int clen = rb_enc_fast_mbclen(s, e, enc);
7907
7908 p -= clen;
7909 memcpy(p, s, clen);
7910 s += clen;
7911 }
7912 }
7913 else {
7914 cr = rb_enc_asciicompat(enc) ?
7916 while (s < e) {
7917 int clen = rb_enc_mbclen(s, e, enc);
7918
7919 if (clen > 1 || (*s & 0x80)) cr = ENC_CODERANGE_UNKNOWN;
7920 p -= clen;
7921 memcpy(p, s, clen);
7922 s += clen;
7923 }
7924 }
7925 }
7926 STR_SET_LEN(rev, RSTRING_LEN(str));
7927 str_enc_copy_direct(rev, str);
7928 ENC_CODERANGE_SET(rev, cr);
7929
7930 return rev;
7931}
7932
7933
7934/*
7935 * call-seq:
7936 * reverse! -> self
7937 *
7938 * Returns +self+ with its characters reversed:
7939 *
7940 * 'drawer'.reverse! # => "reward"
7941 * 'reviled'.reverse! # => "deliver"
7942 * 'stressed'.reverse! # => "desserts"
7943 * 'semordnilaps'.reverse! # => "spalindromes"
7944 *
7945 * Related: see {Modifying}[rdoc-ref:String@Modifying].
7946 */
7947
7948static VALUE
7949rb_str_reverse_bang(VALUE str)
7950{
7951 if (RSTRING_LEN(str) > 1) {
7952 if (single_byte_optimizable(str)) {
7953 char *s, *e, c;
7954
7955 str_modify_keep_cr(str);
7956 s = RSTRING_PTR(str);
7957 e = RSTRING_END(str) - 1;
7958 while (s < e) {
7959 c = *s;
7960 *s++ = *e;
7961 *e-- = c;
7962 }
7963 }
7964 else {
7965 str_shared_replace(str, rb_str_reverse(str));
7966 }
7967 }
7968 else {
7969 str_modify_keep_cr(str);
7970 }
7971 return str;
7972}
7973
7974
7975/*
7976 * call-seq:
7977 * include?(other_string) -> true or false
7978 *
7979 * Returns whether +self+ contains +other_string+:
7980 *
7981 * s = 'bar'
7982 * s.include?('ba') # => true
7983 * s.include?('ar') # => true
7984 * s.include?('bar') # => true
7985 * s.include?('a') # => true
7986 * s.include?('') # => true
7987 * s.include?('foo') # => false
7988 *
7989 * Related: see {Querying}[rdoc-ref:String@Querying].
7990 */
7991
7992VALUE
7993rb_str_include(VALUE str, VALUE arg)
7994{
7995 rb_len_t i;
7996
7997 StringValue(arg);
7998 i = rb_str_index(str, arg, 0);
7999
8000 return RBOOL(i != -1);
8001}
8002
8003
8004/*
8005 * call-seq:
8006 * to_i(base = 10) -> integer
8007 *
8008 * Returns the result of interpreting leading characters in +self+
8009 * as an integer in the given +base+;
8010 * +base+ must be either +0+ or in range <tt>(2..36)</tt>:
8011 *
8012 * '123456'.to_i # => 123456
8013 * '123def'.to_i(16) # => 1195503
8014 *
8015 * With +base+ zero given, string +object+ may contain leading characters
8016 * to specify the actual base:
8017 *
8018 * '123def'.to_i(0) # => 123
8019 * '0123def'.to_i(0) # => 83
8020 * '0b123def'.to_i(0) # => 1
8021 * '0o123def'.to_i(0) # => 83
8022 * '0d123def'.to_i(0) # => 123
8023 * '0x123def'.to_i(0) # => 1195503
8024 *
8025 * Characters past a leading valid number (in the given +base+) are ignored:
8026 *
8027 * '12.345'.to_i # => 12
8028 * '12345'.to_i(2) # => 1
8029 *
8030 * Returns zero if there is no leading valid number:
8031 *
8032 * 'abcdef'.to_i # => 0
8033 * '2'.to_i(2) # => 0
8034 *
8035 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
8036 */
8037
8038static VALUE
8039rb_str_to_i(int argc, VALUE *argv, VALUE str)
8040{
8041 int base = 10;
8042
8043 if (rb_check_arity(argc, 0, 1) && (base = NUM2INT(argv[0])) < 0) {
8044 rb_raise(rb_eArgError, "invalid radix %d", base);
8045 }
8046 return rb_str_to_inum(str, base, FALSE);
8047}
8048
8049
8050/*
8051 * call-seq:
8052 * to_f -> float
8053 *
8054 * Returns the result of interpreting leading characters in +self+ as a Float:
8055 *
8056 * '3.14159'.to_f # => 3.14159
8057 * '1.234e-2'.to_f # => 0.01234
8058 *
8059 * Characters past a leading valid number are ignored:
8060 *
8061 * '3.14 (pi to two places)'.to_f # => 3.14
8062 *
8063 * Returns zero if there is no leading valid number:
8064 *
8065 * 'abcdef'.to_f # => 0.0
8066 *
8067 * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
8068 */
8069
8070static VALUE
8071rb_str_to_f(VALUE str)
8072{
8073 return DBL2NUM(rb_str_to_dbl(str, FALSE));
8074}
8075
8076
8077/*
8078 * call-seq:
8079 * to_s -> self or new_string
8080 *
8081 * Returns +self+ if +self+ is a +String+,
8082 * or +self+ converted to a +String+ if +self+ is a subclass of +String+.
8083 *
8084 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8085 */
8086
8087static VALUE
8088rb_str_to_s(VALUE str)
8089{
8090 if (rb_obj_class(str) != rb_cString) {
8091 return str_duplicate(rb_cString, str);
8092 }
8093 return str;
8094}
8095
8096#if 0
8097static void
8098str_cat_char(VALUE str, unsigned int c, rb_encoding *enc)
8099{
8100 char s[RUBY_MAX_CHAR_LEN];
8101 int n = rb_enc_codelen(c, enc);
8102
8103 rb_enc_mbcput(c, s, enc);
8104 rb_enc_str_buf_cat(str, s, n, enc);
8105}
8106#endif
8107
8108#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */
8109
8110int
8111rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p)
8112{
8113 char buf[CHAR_ESC_LEN + 1];
8114 int l;
8115
8116#if SIZEOF_INT > 4
8117 c &= 0xffffffff;
8118#endif
8119 if (unicode_p) {
8120 if (c < 0x7F && ISPRINT(c)) {
8121 snprintf(buf, CHAR_ESC_LEN, "%c", c);
8122 }
8123 else if (c < 0x10000) {
8124 snprintf(buf, CHAR_ESC_LEN, "\\u%04X", c);
8125 }
8126 else {
8127 snprintf(buf, CHAR_ESC_LEN, "\\u{%X}", c);
8128 }
8129 }
8130 else {
8131 if (c < 0x100) {
8132 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", c);
8133 }
8134 else {
8135 snprintf(buf, CHAR_ESC_LEN, "\\x{%X}", c);
8136 }
8137 }
8138 l = (int)strlen(buf); /* CHAR_ESC_LEN cannot exceed INT_MAX */
8139 rb_str_buf_cat(result, buf, l);
8140 return l;
8141}
8142
8143const char *
8144ruby_escaped_char(int c)
8145{
8146 switch (c) {
8147 case '\0': return "\\0";
8148 case '\n': return "\\n";
8149 case '\r': return "\\r";
8150 case '\t': return "\\t";
8151 case '\f': return "\\f";
8152 case '\013': return "\\v";
8153 case '\010': return "\\b";
8154 case '\007': return "\\a";
8155 case '\033': return "\\e";
8156 case '\x7f': return "\\c?";
8157 }
8158 return NULL;
8159}
8160
8161VALUE
8162rb_str_escape(VALUE str)
8163{
8164 int encidx = ENCODING_GET(str);
8165 rb_encoding *enc = rb_enc_from_index(encidx);
8166 const char *p = RSTRING_PTR(str);
8167 const char *pend = RSTRING_END(str);
8168 const char *prev = p;
8169 char buf[CHAR_ESC_LEN + 1];
8170 VALUE result = rb_str_buf_new(0);
8171 int unicode_p = rb_enc_unicode_p(enc);
8172 int asciicompat = rb_enc_asciicompat(enc);
8173
8174 while (p < pend) {
8175 unsigned int c;
8176 const char *cc;
8177 int n = rb_enc_precise_mbclen(p, pend, enc);
8178 if (!MBCLEN_CHARFOUND_P(n)) {
8179 if (p > prev) str_buf_cat(result, prev, p - prev);
8180 n = rb_enc_mbminlen(enc);
8181 if (pend < p + n)
8182 n = (int)(pend - p);
8183 while (n--) {
8184 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
8185 str_buf_cat(result, buf, strlen(buf));
8186 prev = ++p;
8187 }
8188 continue;
8189 }
8190 n = MBCLEN_CHARFOUND_LEN(n);
8191 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8192 p += n;
8193 cc = ruby_escaped_char(c);
8194 if (cc) {
8195 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8196 str_buf_cat(result, cc, strlen(cc));
8197 prev = p;
8198 }
8199 else if (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c)) {
8200 }
8201 else {
8202 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8203 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8204 prev = p;
8205 }
8206 }
8207 if (p > prev) str_buf_cat(result, prev, p - prev);
8208 ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
8209
8210 return result;
8211}
8212
8213/* Lookup table for the inspect fast path. 1 marks bytes that need
8214 * no escaping. 0 marks bytes that need escape inspection: 0x00-0x1F
8215 * (control), 0x22 ("), 0x23 (#), 0x5C (\‍), 0x7F (DEL), 0x80-0xFF
8216 * (non-ASCII). */
8217static const bool inspect_no_escape[256] = {
8218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
8219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
8220 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20-0x2F */
8221 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30-0x3F */
8222 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F */
8223 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 0x50-0x5F */
8224 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F */
8225 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 0x70-0x7F */
8226};
8227
8228/*
8229 * call-seq:
8230 * inspect -> string
8231 *
8232 * :include: doc/string/inspect.rdoc
8233 *
8234 */
8235
8236VALUE
8238{
8239 int encidx = ENCODING_GET(str);
8240 rb_encoding *enc = rb_enc_from_index(encidx);
8241 const char *p, *pend, *prev;
8242 char buf[CHAR_ESC_LEN + 1];
8243 VALUE result = rb_str_buf_new(RSTRING_LEN(str) + 2); /* string content + surrounding quotes */
8244 rb_encoding *resenc = rb_default_internal_encoding();
8245 int unicode_p = rb_enc_unicode_p(enc);
8246 int asciicompat = rb_enc_asciicompat(enc);
8247 int cr = rb_enc_str_coderange(str);
8248
8249 if (resenc == NULL) resenc = rb_default_external_encoding();
8250 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8251 rb_enc_associate(result, resenc);
8252 str_buf_cat2(result, "\"");
8253
8254 p = RSTRING_PTR(str); pend = RSTRING_END(str);
8255 prev = p;
8256 while (p < pend) {
8257 unsigned int c, cc;
8258 int n;
8259
8260 /* Fast path: bulk-skip runs of safe ASCII bytes via a lookup table.
8261 * Only well-formed strings (CR=7BIT for any encoding, or UTF-8 VALID)
8262 * are eligible. */
8263 if (cr == ENC_CODERANGE_7BIT ||
8264 (encidx == ENCINDEX_UTF_8 && cr == ENC_CODERANGE_VALID)) {
8265 while (p < pend && inspect_no_escape[(unsigned char)*p]) p++;
8266 if (p >= pend) break;
8267 }
8268
8269 n = rb_enc_precise_mbclen(p, pend, enc);
8270 if (!MBCLEN_CHARFOUND_P(n)) {
8271 if (p > prev) str_buf_cat(result, prev, p - prev);
8272 n = rb_enc_mbminlen(enc);
8273 if (pend < p + n)
8274 n = (int)(pend - p);
8275 while (n--) {
8276 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
8277 str_buf_cat(result, buf, strlen(buf));
8278 prev = ++p;
8279 }
8280 continue;
8281 }
8282 n = MBCLEN_CHARFOUND_LEN(n);
8283 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8284 p += n;
8285 if ((asciicompat || unicode_p) &&
8286 (c == '"'|| c == '\\' ||
8287 (c == '#' &&
8288 p < pend &&
8289 MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
8290 (cc = rb_enc_codepoint(p,pend,enc),
8291 (cc == '$' || cc == '@' || cc == '{'))))) {
8292 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8293 str_buf_cat2(result, "\\");
8294 if (asciicompat || enc == resenc) {
8295 prev = p - n;
8296 continue;
8297 }
8298 }
8299 switch (c) {
8300 case '\n': cc = 'n'; break;
8301 case '\r': cc = 'r'; break;
8302 case '\t': cc = 't'; break;
8303 case '\f': cc = 'f'; break;
8304 case '\013': cc = 'v'; break;
8305 case '\010': cc = 'b'; break;
8306 case '\007': cc = 'a'; break;
8307 case 033: cc = 'e'; break;
8308 default: cc = 0; break;
8309 }
8310 if (cc) {
8311 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8312 buf[0] = '\\';
8313 buf[1] = (char)cc;
8314 str_buf_cat(result, buf, 2);
8315 prev = p;
8316 continue;
8317 }
8318 /* The special casing of 0x85 (NEXT_LINE) here is because
8319 * Oniguruma historically treats it as printable, but it
8320 * doesn't match the print POSIX bracket class or character
8321 * property in regexps.
8322 *
8323 * See Ruby Bug #16842 for details:
8324 * https://bugs.ruby-lang.org/issues/16842
8325 */
8326 if ((enc == resenc && rb_enc_isprint(c, enc) && c != 0x85) ||
8327 (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c))) {
8328 continue;
8329 }
8330 else {
8331 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8332 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8333 prev = p;
8334 continue;
8335 }
8336 }
8337 if (p > prev) str_buf_cat(result, prev, p - prev);
8338 str_buf_cat2(result, "\"");
8339
8340 return result;
8341}
8342
8343#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8344
8345/*
8346 * call-seq:
8347 * dump -> new_string
8348 *
8349 * :include: doc/string/dump.rdoc
8350 *
8351 */
8352
8353VALUE
8355{
8356 int encidx = rb_enc_get_index(str);
8357 rb_encoding *enc = rb_enc_from_index(encidx);
8358 rb_len_t len;
8359 const char *p, *pend;
8360 char *q, *qend;
8361 VALUE result;
8362 int u8 = (encidx == rb_utf8_encindex());
8363 static const char nonascii_suffix[] = ".dup.force_encoding(\"%s\")";
8364
8365 len = 2; /* "" */
8366 if (!rb_enc_asciicompat(enc)) {
8367 len += strlen(nonascii_suffix) - rb_strlen_lit("%s");
8368 len += strlen(enc->name);
8369 }
8370
8371 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8372 while (p < pend) {
8373 int clen;
8374 unsigned char c = *p++;
8375
8376 switch (c) {
8377 case '"': case '\\':
8378 case '\n': case '\r':
8379 case '\t': case '\f':
8380 case '\013': case '\010': case '\007': case '\033':
8381 clen = 2;
8382 break;
8383
8384 case '#':
8385 clen = IS_EVSTR(p, pend) ? 2 : 1;
8386 break;
8387
8388 default:
8389 if (ISPRINT(c)) {
8390 clen = 1;
8391 }
8392 else {
8393 if (u8 && c > 0x7F) { /* \u notation */
8394 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8395 if (MBCLEN_CHARFOUND_P(n)) {
8396 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8397 if (cc <= 0xFFFF)
8398 clen = 6; /* \uXXXX */
8399 else if (cc <= 0xFFFFF)
8400 clen = 9; /* \u{XXXXX} */
8401 else
8402 clen = 10; /* \u{XXXXXX} */
8403 p += MBCLEN_CHARFOUND_LEN(n)-1;
8404 break;
8405 }
8406 }
8407 clen = 4; /* \xNN */
8408 }
8409 break;
8410 }
8411
8412 if (clen > RB_LEN_MAX - len) {
8413 rb_raise(rb_eRuntimeError, "string size too big");
8414 }
8415 len += clen;
8416 }
8417
8418 result = rb_str_new(0, len);
8419 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8420 q = RSTRING_PTR(result); qend = q + len + 1;
8421
8422 *q++ = '"';
8423 while (p < pend) {
8424 unsigned char c = *p++;
8425
8426 if (c == '"' || c == '\\') {
8427 *q++ = '\\';
8428 *q++ = c;
8429 }
8430 else if (c == '#') {
8431 if (IS_EVSTR(p, pend)) *q++ = '\\';
8432 *q++ = '#';
8433 }
8434 else if (c == '\n') {
8435 *q++ = '\\';
8436 *q++ = 'n';
8437 }
8438 else if (c == '\r') {
8439 *q++ = '\\';
8440 *q++ = 'r';
8441 }
8442 else if (c == '\t') {
8443 *q++ = '\\';
8444 *q++ = 't';
8445 }
8446 else if (c == '\f') {
8447 *q++ = '\\';
8448 *q++ = 'f';
8449 }
8450 else if (c == '\013') {
8451 *q++ = '\\';
8452 *q++ = 'v';
8453 }
8454 else if (c == '\010') {
8455 *q++ = '\\';
8456 *q++ = 'b';
8457 }
8458 else if (c == '\007') {
8459 *q++ = '\\';
8460 *q++ = 'a';
8461 }
8462 else if (c == '\033') {
8463 *q++ = '\\';
8464 *q++ = 'e';
8465 }
8466 else if (ISPRINT(c)) {
8467 *q++ = c;
8468 }
8469 else {
8470 *q++ = '\\';
8471 if (u8) {
8472 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8473 if (MBCLEN_CHARFOUND_P(n)) {
8474 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8475 p += n;
8476 if (cc <= 0xFFFF)
8477 snprintf(q, qend-q, "u%04X", cc); /* \uXXXX */
8478 else
8479 snprintf(q, qend-q, "u{%X}", cc); /* \u{XXXXX} or \u{XXXXXX} */
8480 q += strlen(q);
8481 continue;
8482 }
8483 }
8484 snprintf(q, qend-q, "x%02X", c);
8485 q += 3;
8486 }
8487 }
8488 *q++ = '"';
8489 *q = '\0';
8490 if (!rb_enc_asciicompat(enc)) {
8491 snprintf(q, qend-q, nonascii_suffix, enc->name);
8492 encidx = rb_ascii8bit_encindex();
8493 }
8494 /* result from dump is ASCII */
8495 rb_enc_associate_index(result, encidx);
8497 return result;
8498}
8499
8500static int
8501unescape_ascii(unsigned int c)
8502{
8503 switch (c) {
8504 case 'n':
8505 return '\n';
8506 case 'r':
8507 return '\r';
8508 case 't':
8509 return '\t';
8510 case 'f':
8511 return '\f';
8512 case 'v':
8513 return '\13';
8514 case 'b':
8515 return '\010';
8516 case 'a':
8517 return '\007';
8518 case 'e':
8519 return 033;
8520 }
8522}
8523
8524static void
8525undump_after_backslash(VALUE undumped, const char **ss, const char *s_end, rb_encoding **penc, bool *utf8, bool *binary)
8526{
8527 const char *s = *ss;
8528 unsigned int c;
8529 int codelen;
8530 size_t hexlen;
8531 unsigned char buf[6];
8532 static rb_encoding *enc_utf8 = NULL;
8533
8534 switch (*s) {
8535 case '\\':
8536 case '"':
8537 case '#':
8538 rb_str_cat(undumped, s, 1); /* cat itself */
8539 s++;
8540 break;
8541 case 'n':
8542 case 'r':
8543 case 't':
8544 case 'f':
8545 case 'v':
8546 case 'b':
8547 case 'a':
8548 case 'e':
8549 *buf = unescape_ascii(*s);
8550 rb_str_cat(undumped, (char *)buf, 1);
8551 s++;
8552 break;
8553 case 'u':
8554 if (*binary) {
8555 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8556 }
8557 *utf8 = true;
8558 if (++s >= s_end) {
8559 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8560 }
8561 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8562 if (*penc != enc_utf8) {
8563 *penc = enc_utf8;
8564 rb_enc_associate(undumped, enc_utf8);
8565 }
8566 if (*s == '{') { /* handle \u{...} form */
8567 s++;
8568 for (;;) {
8569 if (s >= s_end) {
8570 rb_raise(rb_eRuntimeError, "unterminated Unicode escape");
8571 }
8572 if (*s == '}') {
8573 s++;
8574 break;
8575 }
8576 if (ISSPACE(*s)) {
8577 s++;
8578 continue;
8579 }
8580 c = scan_hex(s, s_end-s, &hexlen);
8581 if (hexlen == 0 || hexlen > 6) {
8582 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8583 }
8584 if (c > 0x10ffff) {
8585 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint (too large)");
8586 }
8587 if (0xd800 <= c && c <= 0xdfff) {
8588 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8589 }
8590 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8591 rb_str_cat(undumped, (char *)buf, codelen);
8592 s += hexlen;
8593 }
8594 }
8595 else { /* handle \uXXXX form */
8596 c = scan_hex(s, 4, &hexlen);
8597 if (hexlen != 4) {
8598 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
8599 }
8600 if (0xd800 <= c && c <= 0xdfff) {
8601 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
8602 }
8603 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
8604 rb_str_cat(undumped, (char *)buf, codelen);
8605 s += hexlen;
8606 }
8607 break;
8608 case 'x':
8609 if (++s >= s_end) {
8610 rb_raise(rb_eRuntimeError, "invalid hex escape");
8611 }
8612 *buf = scan_hex(s, 2, &hexlen);
8613 if (hexlen != 2) {
8614 rb_raise(rb_eRuntimeError, "invalid hex escape");
8615 }
8616 if (!ISASCII(*buf)) {
8617 if (*utf8) {
8618 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
8619 }
8620 *binary = true;
8621 }
8622 rb_str_cat(undumped, (char *)buf, 1);
8623 s += hexlen;
8624 break;
8625 default:
8626 rb_str_cat(undumped, s-1, 2);
8627 s++;
8628 }
8629
8630 *ss = s;
8631}
8632
8633static VALUE rb_str_is_ascii_only_p(VALUE str);
8634
8635/*
8636 * call-seq:
8637 * undump -> new_string
8638 *
8639 * Inverse of String#dump; returns a copy of +self+ with changes of the kinds made by String#dump "undone."
8640 *
8641 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8642 */
8643
8644static VALUE
8645str_undump(VALUE str)
8646{
8647 const char *s = RSTRING_PTR(str);
8648 const char *s_end = RSTRING_END(str);
8649 rb_encoding *enc = rb_enc_get(str);
8650 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8651 bool utf8 = false;
8652 bool binary = false;
8653 int w;
8654
8656 if (rb_str_is_ascii_only_p(str) == Qfalse) {
8657 rb_raise(rb_eRuntimeError, "non-ASCII character detected");
8658 }
8659 if (!str_null_check(str, &w)) {
8660 rb_raise(rb_eRuntimeError, "string contains null byte");
8661 }
8662 if (RSTRING_LEN(str) < 2) goto invalid_format;
8663 if (*s != '"') goto invalid_format;
8664
8665 /* strip '"' at the start */
8666 s++;
8667
8668 for (;;) {
8669 if (s >= s_end) {
8670 rb_raise(rb_eRuntimeError, "unterminated dumped string");
8671 }
8672
8673 if (*s == '"') {
8674 /* epilogue */
8675 s++;
8676 if (s == s_end) {
8677 /* ascii compatible dumped string */
8678 break;
8679 }
8680 else {
8681 static const char force_encoding_suffix[] = ".force_encoding(\""; /* "\")" */
8682 static const char dup_suffix[] = ".dup";
8683 const char *encname;
8684 int encidx;
8685 ptrdiff_t size;
8686
8687 /* check separately for strings dumped by older versions */
8688 size = sizeof(dup_suffix) - 1;
8689 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8690
8691 size = sizeof(force_encoding_suffix) - 1;
8692 if (s_end - s <= size) goto invalid_format;
8693 if (memcmp(s, force_encoding_suffix, size) != 0) goto invalid_format;
8694 s += size;
8695
8696 if (utf8) {
8697 rb_raise(rb_eRuntimeError, "dumped string contained Unicode escape but used force_encoding");
8698 }
8699
8700 encname = s;
8701 s = memchr(s, '"', s_end-s);
8702 size = s - encname;
8703 if (!s) goto invalid_format;
8704 if (s_end - s != 2) goto invalid_format;
8705 if (s[0] != '"' || s[1] != ')') goto invalid_format;
8706
8707 encidx = rb_enc_find_index2(encname, (rb_len_t)size);
8708 if (encidx < 0) {
8709 rb_raise(rb_eRuntimeError, "dumped string has unknown encoding name");
8710 }
8711 rb_enc_associate_index(undumped, encidx);
8712 }
8713 break;
8714 }
8715
8716 if (*s == '\\') {
8717 s++;
8718 if (s >= s_end) {
8719 rb_raise(rb_eRuntimeError, "invalid escape");
8720 }
8721 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8722 }
8723 else {
8724 rb_str_cat(undumped, s++, 1);
8725 }
8726 }
8727
8728 RB_GC_GUARD(str);
8729
8730 return undumped;
8731invalid_format:
8732 rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8733}
8734
8735static void
8736rb_str_check_dummy_enc(rb_encoding *enc)
8737{
8738 if (rb_enc_dummy_p(enc)) {
8739 rb_raise(rb_eEncCompatError, "incompatible encoding with this operation: %s",
8740 rb_enc_name(enc));
8741 }
8742}
8743
8744static rb_encoding *
8745str_true_enc(VALUE str)
8746{
8747 rb_encoding *enc = STR_ENC_GET(str);
8748 rb_str_check_dummy_enc(enc);
8749 return enc;
8750}
8751
8752static OnigCaseFoldType
8753check_case_options(int argc, VALUE *argv, OnigCaseFoldType flags)
8754{
8755 if (argc==0)
8756 return flags;
8757 if (argc>2)
8758 rb_raise(rb_eArgError, "too many options");
8759 if (argv[0]==sym_turkic) {
8760 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8761 if (argc==2) {
8762 if (argv[1]==sym_lithuanian)
8763 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8764 else
8765 rb_raise(rb_eArgError, "invalid second option");
8766 }
8767 }
8768 else if (argv[0]==sym_lithuanian) {
8769 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8770 if (argc==2) {
8771 if (argv[1]==sym_turkic)
8772 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8773 else
8774 rb_raise(rb_eArgError, "invalid second option");
8775 }
8776 }
8777 else if (argc>1)
8778 rb_raise(rb_eArgError, "too many options");
8779 else if (argv[0]==sym_ascii)
8780 flags |= ONIGENC_CASE_ASCII_ONLY;
8781 else if (argv[0]==sym_fold) {
8782 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8783 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8784 else
8785 rb_raise(rb_eArgError, "option :fold only allowed for downcasing");
8786 }
8787 else
8788 rb_raise(rb_eArgError, "invalid option");
8789 return flags;
8790}
8791
8792static inline bool
8793case_option_single_p(OnigCaseFoldType flags, rb_encoding *enc, VALUE str)
8794{
8795 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() || rb_enc_mbmaxlen(enc) == 1))
8796 return true;
8797 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8798 (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT || rb_is_ascii8bit_enc(enc));
8799}
8800
8801/* 16 should be long enough to absorb any kind of single character length increase */
8802#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8803#ifndef CASEMAP_DEBUG
8804# define CASEMAP_DEBUG 0
8805#endif
8806
8807struct mapping_buffer;
8808typedef struct mapping_buffer {
8809 size_t capa;
8810 size_t used;
8811 struct mapping_buffer *next;
8812 OnigUChar space[FLEX_ARY_LEN];
8814
8815static void
8816mapping_buffer_free(void *p)
8817{
8818 mapping_buffer *previous_buffer;
8819 mapping_buffer *current_buffer = p;
8820 while (current_buffer) {
8821 previous_buffer = current_buffer;
8822 current_buffer = current_buffer->next;
8823 ruby_xfree_sized(previous_buffer, offsetof(mapping_buffer, space) + previous_buffer->capa);
8824 }
8825}
8826
8827static const rb_data_type_t mapping_buffer_type = {
8828 "mapping_buffer",
8829 {0, mapping_buffer_free,},
8830 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8831};
8832
8833static VALUE
8834rb_str_casemap(VALUE source, OnigCaseFoldType *flags, rb_encoding *enc)
8835{
8836 VALUE target;
8837
8838 const OnigUChar *source_current, *source_end;
8839 int target_length = 0;
8840 VALUE buffer_anchor;
8841 mapping_buffer *current_buffer = 0;
8842 mapping_buffer **pre_buffer;
8843 size_t buffer_count = 0;
8844 int buffer_length_or_invalid;
8845
8846 if (RSTRING_LEN(source) == 0) return str_duplicate(rb_cString, source);
8847
8848 source_current = (OnigUChar*)RSTRING_PTR(source);
8849 source_end = (OnigUChar*)RSTRING_END(source);
8850
8851 buffer_anchor = TypedData_Wrap_Struct(0, &mapping_buffer_type, 0);
8852 pre_buffer = (mapping_buffer **)&DATA_PTR(buffer_anchor);
8853 while (source_current < source_end) {
8854 /* increase multiplier using buffer count to converge quickly */
8855 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8856 if (CASEMAP_DEBUG) {
8857 fprintf(stderr, "Buffer allocation, capa is %"PRIuSIZE"\n", capa); /* for tuning */
8858 }
8859 current_buffer = xmalloc(offsetof(mapping_buffer, space) + capa);
8860 *pre_buffer = current_buffer;
8861 pre_buffer = &current_buffer->next;
8862 current_buffer->next = NULL;
8863 current_buffer->capa = capa;
8864 buffer_length_or_invalid = enc->case_map(flags,
8865 &source_current, source_end,
8866 current_buffer->space,
8867 current_buffer->space+current_buffer->capa,
8868 enc);
8869 if (buffer_length_or_invalid < 0) {
8870 current_buffer = DATA_PTR(buffer_anchor);
8871 DATA_PTR(buffer_anchor) = 0;
8872 mapping_buffer_free(current_buffer);
8873 rb_raise(rb_eArgError, "input string invalid");
8874 }
8875 target_length += current_buffer->used = buffer_length_or_invalid;
8876 }
8877 if (CASEMAP_DEBUG) {
8878 fprintf(stderr, "Buffer count is %"PRIuSIZE"\n", buffer_count); /* for tuning */
8879 }
8880
8881 if (buffer_count==1) {
8882 target = rb_str_new((const char*)current_buffer->space, target_length);
8883 }
8884 else {
8885 char *target_current;
8886
8887 target = rb_str_new(0, target_length);
8888 target_current = RSTRING_PTR(target);
8889 current_buffer = DATA_PTR(buffer_anchor);
8890 while (current_buffer) {
8891 memcpy(target_current, current_buffer->space, current_buffer->used);
8892 target_current += current_buffer->used;
8893 current_buffer = current_buffer->next;
8894 }
8895 }
8896 current_buffer = DATA_PTR(buffer_anchor);
8897 DATA_PTR(buffer_anchor) = 0;
8898 mapping_buffer_free(current_buffer);
8899
8900 RB_GC_GUARD(buffer_anchor);
8901
8902 /* TODO: check about string terminator character */
8903 str_enc_copy_direct(target, source);
8904 /*ENC_CODERANGE_SET(mapped, cr);*/
8905
8906 return target;
8907}
8908
8909static VALUE
8910rb_str_ascii_casemap(VALUE source, VALUE target, OnigCaseFoldType *flags, rb_encoding *enc)
8911{
8912 const OnigUChar *source_current, *source_end;
8913 OnigUChar *target_current, *target_end;
8914 rb_len_t old_length = RSTRING_LEN(source);
8915 int length_or_invalid;
8916
8917 if (old_length == 0) return Qnil;
8918
8919 source_current = (OnigUChar*)RSTRING_PTR(source);
8920 source_end = (OnigUChar*)RSTRING_END(source);
8921 if (source == target) {
8922 target_current = (OnigUChar*)source_current;
8923 target_end = (OnigUChar*)source_end;
8924 }
8925 else {
8926 target_current = (OnigUChar*)RSTRING_PTR(target);
8927 target_end = (OnigUChar*)RSTRING_END(target);
8928 }
8929
8930 length_or_invalid = onigenc_ascii_only_case_map(flags,
8931 &source_current, source_end,
8932 target_current, target_end, enc);
8933 if (length_or_invalid < 0)
8934 rb_raise(rb_eArgError, "input string invalid");
8935 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8936 fprintf(stderr, "problem with rb_str_ascii_casemap"
8937 "; old_length=%"PRIdLEN", new_length=%d\n", old_length, length_or_invalid);
8938 rb_raise(rb_eArgError, "internal problem with rb_str_ascii_casemap"
8939 "; old_length=%"PRIdLEN", new_length=%d\n", old_length, length_or_invalid);
8940 }
8941
8942 str_enc_copy(target, source);
8943
8944 return target;
8945}
8946
8947static bool
8948upcase_single(VALUE str)
8949{
8950 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8951 bool modified = false;
8952
8953 while (s < send) {
8954 unsigned int c = *(unsigned char*)s;
8955
8956 if ('a' <= c && c <= 'z') {
8957 *s = 'A' + (c - 'a');
8958 modified = true;
8959 }
8960 s++;
8961 }
8962 return modified;
8963}
8964
8965/*
8966 * call-seq:
8967 * upcase!(mapping) -> self or nil
8968 *
8969 * Like String#upcase, except that:
8970 *
8971 * - Changes character casings in +self+ (not in a copy of +self+).
8972 * - Returns +self+ if any changes are made, +nil+ otherwise.
8973 *
8974 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8975 */
8976
8977static VALUE
8978rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
8979{
8980 rb_encoding *enc;
8981 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8982
8983 flags = check_case_options(argc, argv, flags);
8984 str_modify_keep_cr(str);
8985 enc = str_true_enc(str);
8986 if (case_option_single_p(flags, enc, str)) {
8987 if (upcase_single(str))
8988 flags |= ONIGENC_CASE_MODIFIED;
8989 }
8990 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8991 rb_str_ascii_casemap(str, str, &flags, enc);
8992 else
8993 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8994
8995 if (ONIGENC_CASE_MODIFIED&flags) return str;
8996 return Qnil;
8997}
8998
8999
9000/*
9001 * call-seq:
9002 * upcase(mapping) -> new_string
9003 *
9004 * :include: doc/string/upcase.rdoc
9005 */
9006
9007static VALUE
9008rb_str_upcase(int argc, VALUE *argv, VALUE str)
9009{
9010 rb_encoding *enc;
9011 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
9012 VALUE ret;
9013
9014 flags = check_case_options(argc, argv, flags);
9015 enc = str_true_enc(str);
9016 if (case_option_single_p(flags, enc, str)) {
9017 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9018 str_enc_copy_direct(ret, str);
9019 upcase_single(ret);
9020 }
9021 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9022 ret = rb_str_new(0, RSTRING_LEN(str));
9023 rb_str_ascii_casemap(str, ret, &flags, enc);
9024 }
9025 else {
9026 ret = rb_str_casemap(str, &flags, enc);
9027 }
9028
9029 return ret;
9030}
9031
9032static bool
9033downcase_single(VALUE str)
9034{
9035 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
9036 bool modified = false;
9037
9038 while (s < send) {
9039 unsigned int c = *(unsigned char*)s;
9040
9041 if ('A' <= c && c <= 'Z') {
9042 *s = 'a' + (c - 'A');
9043 modified = true;
9044 }
9045 s++;
9046 }
9047
9048 return modified;
9049}
9050
9051/*
9052 * call-seq:
9053 * downcase!(mapping) -> self or nil
9054 *
9055 * Like String#downcase, except that:
9056 *
9057 * - Changes character casings in +self+ (not in a copy of +self+).
9058 * - Returns +self+ if any changes are made, +nil+ otherwise.
9059 *
9060 * Related: See {Modifying}[rdoc-ref:String@Modifying].
9061 */
9062
9063static VALUE
9064rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
9065{
9066 rb_encoding *enc;
9067 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9068
9069 flags = check_case_options(argc, argv, flags);
9070 str_modify_keep_cr(str);
9071 enc = str_true_enc(str);
9072 if (case_option_single_p(flags, enc, str)) {
9073 if (downcase_single(str))
9074 flags |= ONIGENC_CASE_MODIFIED;
9075 }
9076 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9077 rb_str_ascii_casemap(str, str, &flags, enc);
9078 else
9079 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9080
9081 if (ONIGENC_CASE_MODIFIED&flags) return str;
9082 return Qnil;
9083}
9084
9085
9086/*
9087 * call-seq:
9088 * downcase(mapping) -> new_string
9089 *
9090 * :include: doc/string/downcase.rdoc
9091 *
9092 */
9093
9094static VALUE
9095rb_str_downcase(int argc, VALUE *argv, VALUE str)
9096{
9097 rb_encoding *enc;
9098 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9099 VALUE ret;
9100
9101 flags = check_case_options(argc, argv, flags);
9102 enc = str_true_enc(str);
9103 if (case_option_single_p(flags, enc, str)) {
9104 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9105 str_enc_copy_direct(ret, str);
9106 downcase_single(ret);
9107 }
9108 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9109 ret = rb_str_new(0, RSTRING_LEN(str));
9110 rb_str_ascii_casemap(str, ret, &flags, enc);
9111 }
9112 else {
9113 ret = rb_str_casemap(str, &flags, enc);
9114 }
9115
9116 return ret;
9117}
9118
9119static bool
9120capitalize_single(VALUE str)
9121{
9122 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
9123 bool modified = false;
9124
9125 if (s < send) {
9126 unsigned int c = (unsigned char)*s;
9127
9128 if ('a' <= c && c <= 'z') {
9129 *s = 'A' + (c - 'a');
9130 modified = true;
9131 }
9132 s++;
9133 }
9134 while (s < send) {
9135 unsigned int c = (unsigned char)*s;
9136
9137 if ('A' <= c && c <= 'Z') {
9138 *s = 'a' + (c - 'A');
9139 modified = true;
9140 }
9141 s++;
9142 }
9143
9144 return modified;
9145}
9146
9147/*
9148 * call-seq:
9149 * capitalize!(mapping) -> self or nil
9150 *
9151 * Like String#capitalize, except that:
9152 *
9153 * - Changes character casings in +self+ (not in a copy of +self+).
9154 * - Returns +self+ if any changes are made, +nil+ otherwise.
9155 *
9156 * Related: See {Modifying}[rdoc-ref:String@Modifying].
9157 */
9158
9159static VALUE
9160rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
9161{
9162 rb_encoding *enc;
9163 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9164
9165 flags = check_case_options(argc, argv, flags);
9166 str_modify_keep_cr(str);
9167 enc = str_true_enc(str);
9168 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
9169 if (case_option_single_p(flags, enc, str)) {
9170 if (capitalize_single(str))
9171 flags |= ONIGENC_CASE_MODIFIED;
9172 }
9173 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9174 rb_str_ascii_casemap(str, str, &flags, enc);
9175 else
9176 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9177
9178 if (ONIGENC_CASE_MODIFIED&flags) return str;
9179 return Qnil;
9180}
9181
9182
9183/*
9184 * call-seq:
9185 * capitalize(mapping) -> new_string
9186 *
9187 * :include: doc/string/capitalize.rdoc
9188 *
9189 */
9190
9191static VALUE
9192rb_str_capitalize(int argc, VALUE *argv, VALUE str)
9193{
9194 rb_encoding *enc;
9195 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9196 VALUE ret;
9197
9198 flags = check_case_options(argc, argv, flags);
9199 enc = str_true_enc(str);
9200 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str;
9201 if (case_option_single_p(flags, enc, str)) {
9202 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9203 str_enc_copy_direct(ret, str);
9204 capitalize_single(ret);
9205 }
9206 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9207 ret = rb_str_new(0, RSTRING_LEN(str));
9208 rb_str_ascii_casemap(str, ret, &flags, enc);
9209 }
9210 else {
9211 ret = rb_str_casemap(str, &flags, enc);
9212 }
9213 return ret;
9214}
9215
9216
9217/*
9218 * call-seq:
9219 * swapcase!(mapping) -> self or nil
9220 *
9221 * Like String#swapcase, except that:
9222 *
9223 * - Changes are made to +self+, not to copy of +self+.
9224 * - Returns +self+ if any changes are made, +nil+ otherwise.
9225 *
9226 * Related: see {Modifying}[rdoc-ref:String@Modifying].
9227 */
9228
9229static VALUE
9230rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
9231{
9232 rb_encoding *enc;
9233 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9234
9235 flags = check_case_options(argc, argv, flags);
9236 str_modify_keep_cr(str);
9237 enc = str_true_enc(str);
9238 if (flags&ONIGENC_CASE_ASCII_ONLY)
9239 rb_str_ascii_casemap(str, str, &flags, enc);
9240 else
9241 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9242
9243 if (ONIGENC_CASE_MODIFIED&flags) return str;
9244 return Qnil;
9245}
9246
9247
9248/*
9249 * call-seq:
9250 * swapcase(mapping) -> new_string
9251 *
9252 * :include: doc/string/swapcase.rdoc
9253 *
9254 */
9255
9256static VALUE
9257rb_str_swapcase(int argc, VALUE *argv, VALUE str)
9258{
9259 rb_encoding *enc;
9260 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9261 VALUE ret;
9262
9263 flags = check_case_options(argc, argv, flags);
9264 enc = str_true_enc(str);
9265 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str_duplicate(rb_cString, str);
9266 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9267 ret = rb_str_new(0, RSTRING_LEN(str));
9268 rb_str_ascii_casemap(str, ret, &flags, enc);
9269 }
9270 else {
9271 ret = rb_str_casemap(str, &flags, enc);
9272 }
9273 return ret;
9274}
9275
9276typedef unsigned char *USTR;
9277
9278struct tr {
9279 int gen;
9280 unsigned int now, max;
9281 const char *p, *pend;
9282};
9283
9284static unsigned int
9285trnext(struct tr *t, rb_encoding *enc)
9286{
9287 int n;
9288
9289 for (;;) {
9290 nextpart:
9291 if (!t->gen) {
9292 if (t->p == t->pend) return -1;
9293 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '\\' && t->p + n < t->pend) {
9294 t->p += n;
9295 }
9296 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9297 t->p += n;
9298 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '-' && t->p + n < t->pend) {
9299 t->p += n;
9300 if (t->p < t->pend) {
9301 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9302 t->p += n;
9303 if (t->now > c) {
9304 if (t->now < 0x80 && c < 0x80) {
9305 rb_raise(rb_eArgError,
9306 "invalid range \"%c-%c\" in string transliteration",
9307 t->now, c);
9308 }
9309 else {
9310 rb_raise(rb_eArgError, "invalid range in string transliteration");
9311 }
9312 continue; /* not reached */
9313 }
9314 else if (t->now < c) {
9315 t->gen = 1;
9316 t->max = c;
9317 }
9318 }
9319 }
9320 return t->now;
9321 }
9322 else {
9323 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9324 if (t->now == t->max) {
9325 t->gen = 0;
9326 goto nextpart;
9327 }
9328 }
9329 if (t->now < t->max) {
9330 return t->now;
9331 }
9332 else {
9333 t->gen = 0;
9334 return t->max;
9335 }
9336 }
9337 }
9338}
9339
9340static VALUE rb_str_delete_bang(int,VALUE*,VALUE);
9341
9342static VALUE
9343tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
9344{
9345 const unsigned int errc = -1;
9346 unsigned int trans[256];
9347 rb_encoding *enc, *e1, *e2;
9348 struct tr trsrc, trrepl;
9349 int cflag = 0;
9350 unsigned int c, c0, last = 0;
9351 int modify = 0, i, l;
9352 unsigned char *s, *send;
9353 VALUE hash = 0;
9354 int singlebyte = single_byte_optimizable(str);
9355 int termlen;
9356 int cr;
9357
9358#define CHECK_IF_ASCII(c) \
9359 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9360 (cr = ENC_CODERANGE_VALID) : 0)
9361
9362 StringValue(src);
9363 StringValue(repl);
9364 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
9365 if (RSTRING_LEN(repl) == 0) {
9366 return rb_str_delete_bang(1, &src, str);
9367 }
9368
9369 cr = ENC_CODERANGE(str);
9370 e1 = rb_enc_check(str, src);
9371 e2 = rb_enc_check(str, repl);
9372 if (e1 == e2) {
9373 enc = e1;
9374 }
9375 else {
9376 enc = rb_enc_check(src, repl);
9377 }
9378 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9379 if (RSTRING_LEN(src) > 1 &&
9380 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) == '^' &&
9381 trsrc.p + l < trsrc.pend) {
9382 cflag = 1;
9383 trsrc.p += l;
9384 }
9385 trrepl.p = RSTRING_PTR(repl);
9386 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9387 trsrc.gen = trrepl.gen = 0;
9388 trsrc.now = trrepl.now = 0;
9389 trsrc.max = trrepl.max = 0;
9390
9391 if (cflag) {
9392 for (i=0; i<256; i++) {
9393 trans[i] = 1;
9394 }
9395 while ((c = trnext(&trsrc, enc)) != errc) {
9396 if (c < 256) {
9397 trans[c] = errc;
9398 }
9399 else {
9400 if (!hash) hash = rb_hash_new();
9401 rb_hash_aset(hash, UINT2NUM(c), Qtrue);
9402 }
9403 }
9404 while ((c = trnext(&trrepl, enc)) != errc)
9405 /* retrieve last replacer */;
9406 last = trrepl.now;
9407 for (i=0; i<256; i++) {
9408 if (trans[i] != errc) {
9409 trans[i] = last;
9410 }
9411 }
9412 }
9413 else {
9414 unsigned int r;
9415
9416 for (i=0; i<256; i++) {
9417 trans[i] = errc;
9418 }
9419 while ((c = trnext(&trsrc, enc)) != errc) {
9420 r = trnext(&trrepl, enc);
9421 if (r == errc) r = trrepl.now;
9422 if (c < 256) {
9423 trans[c] = r;
9424 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9425 }
9426 else {
9427 if (!hash) hash = rb_hash_new();
9428 rb_hash_aset(hash, UINT2NUM(c), UINT2NUM(r));
9429 }
9430 }
9431 }
9432
9433 if (cr == ENC_CODERANGE_VALID && rb_enc_asciicompat(e1))
9434 cr = ENC_CODERANGE_7BIT;
9435 str_modify_keep_cr(str);
9436 s = (unsigned char *)RSTRING_PTR(str); send = (unsigned char *)RSTRING_END(str);
9437 termlen = rb_enc_mbminlen(enc);
9438 if (sflag) {
9439 int clen, tlen;
9440 rb_len_t offset, max = RSTRING_LEN(str);
9441 unsigned int save = -1;
9442 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9443
9444 while (s < send) {
9445 int may_modify = 0;
9446
9447 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9448 if (!MBCLEN_CHARFOUND_P(r)) {
9449 SIZED_FREE_N(buf, max + termlen);
9450 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9451 }
9452 clen = MBCLEN_CHARFOUND_LEN(r);
9453 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9454
9455 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9456
9457 s += clen;
9458 if (c < 256) {
9459 c = trans[c];
9460 }
9461 else if (hash) {
9462 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9463 if (NIL_P(tmp)) {
9464 if (cflag) c = last;
9465 else c = errc;
9466 }
9467 else if (cflag) c = errc;
9468 else c = NUM2INT(tmp);
9469 }
9470 else {
9471 c = errc;
9472 }
9473 if (c != (unsigned int)-1) {
9474 if (save == c) {
9475 CHECK_IF_ASCII(c);
9476 continue;
9477 }
9478 save = c;
9479 tlen = rb_enc_codelen(c, enc);
9480 modify = 1;
9481 }
9482 else {
9483 save = -1;
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 + (send - s);
9490 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9491 t = buf + offset;
9492 }
9493 rb_enc_mbcput(c, t, enc);
9494 if (may_modify && memcmp(s, t, tlen) != 0) {
9495 modify = 1;
9496 }
9497 CHECK_IF_ASCII(c);
9498 t += tlen;
9499 }
9500 if (!STR_EMBED_P(str)) {
9501 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9502 }
9503 TERM_FILL((char *)t, termlen);
9504 RSTRING(str)->as.heap.ptr = (char *)buf;
9505 STR_SET_LEN(str, t - buf);
9506 STR_SET_NOEMBED(str);
9507 RSTRING(str)->as.heap.aux.capa = max;
9508 }
9509 else if (rb_enc_mbmaxlen(enc) == 1 || (singlebyte && !hash)) {
9510 while (s < send) {
9511 c = (unsigned char)*s;
9512 if (trans[c] != errc) {
9513 if (!cflag) {
9514 c = trans[c];
9515 *s = c;
9516 modify = 1;
9517 }
9518 else {
9519 *s = last;
9520 modify = 1;
9521 }
9522 }
9523 CHECK_IF_ASCII(c);
9524 s++;
9525 }
9526 }
9527 else {
9528 int clen, tlen;
9529 rb_len_t offset, max = (rb_len_t)((send - s) * 1.2);
9530 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
9531
9532 while (s < send) {
9533 int may_modify = 0;
9534
9535 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9536 if (!MBCLEN_CHARFOUND_P(r)) {
9537 SIZED_FREE_N(buf, max + termlen);
9538 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
9539 }
9540 clen = MBCLEN_CHARFOUND_LEN(r);
9541 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
9542
9543 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9544
9545 if (c < 256) {
9546 c = trans[c];
9547 }
9548 else if (hash) {
9549 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
9550 if (NIL_P(tmp)) {
9551 if (cflag) c = last;
9552 else c = errc;
9553 }
9554 else if (cflag) c = errc;
9555 else c = NUM2INT(tmp);
9556 }
9557 else {
9558 c = cflag ? last : errc;
9559 }
9560 if (c != errc) {
9561 tlen = rb_enc_codelen(c, enc);
9562 modify = 1;
9563 }
9564 else {
9565 c = c0;
9566 if (enc != e1) may_modify = 1;
9567 }
9568 if ((offset = t - buf) + tlen > max) {
9569 size_t MAYBE_UNUSED(old) = max + termlen;
9570 max = offset + tlen + (rb_len_t)((send - s) * 1.2);
9571 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
9572 t = buf + offset;
9573 }
9574
9575 rb_enc_mbcput(c, t, enc);
9576 if (may_modify && memcmp(s, t, tlen) != 0) {
9577 modify = 1;
9578 }
9579 CHECK_IF_ASCII(c);
9580 s += clen;
9581 t += tlen;
9582 }
9583 if (!STR_EMBED_P(str)) {
9584 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9585 }
9586 TERM_FILL((char *)t, termlen);
9587 RSTRING(str)->as.heap.ptr = (char *)buf;
9588 STR_SET_LEN(str, t - buf);
9589 STR_SET_NOEMBED(str);
9590 RSTRING(str)->as.heap.aux.capa = max;
9591 }
9592
9593 if (modify) {
9594 if (cr != ENC_CODERANGE_BROKEN)
9595 ENC_CODERANGE_SET(str, cr);
9596 rb_enc_associate(str, enc);
9597 return str;
9598 }
9599 return Qnil;
9600}
9601
9603 unsigned char *buf;
9604 unsigned char *ptr;
9605 size_t capa;
9606 size_t initial_capa;
9607};
9608
9609static inline void
9610tr_buffer_init(struct tr_buffer *buffer, size_t initial_capa)
9611{
9612 if (initial_capa < 32) {
9613 initial_capa = 32;
9614 }
9615 *buffer = (struct tr_buffer){ .initial_capa = initial_capa };
9616}
9617
9618static inline void
9619tr_buffer_ensure_capa(struct tr_buffer *buffer, size_t extra_capa)
9620{
9621 size_t offset = buffer->ptr - buffer->buf;
9622 size_t required_capa = offset + extra_capa;
9623 if (UNLIKELY(buffer->capa < required_capa)) {
9624 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9625 RUBY_ASSERT(new_capa >= 32); // Lower would cause infinite loop
9626 while (new_capa < required_capa) {
9627 new_capa = (size_t)(new_capa * 1.2);
9628 }
9629 SIZED_REALLOC_N(buffer->buf, unsigned char, new_capa, buffer->capa);
9630 buffer->ptr = buffer->buf + offset;
9631 buffer->capa = new_capa;
9632 }
9633}
9634
9635static inline void
9636tr_buffer_append(struct tr_buffer *buffer, const unsigned char *ptr, size_t len)
9637{
9638 if (len) {
9639 tr_buffer_ensure_capa(buffer, len);
9640 memcpy(buffer->ptr, ptr, len);
9641 buffer->ptr += len;
9642 }
9643}
9644
9645static inline void
9646tr_buffer_append_str(struct tr_buffer *buffer, VALUE str)
9647{
9648 tr_buffer_append(buffer, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9649}
9650
9651static inline void
9652tr_buffer_mbcput(struct tr_buffer *buffer, int codepoint, rb_encoding *enc)
9653{
9654 tr_buffer_ensure_capa(buffer, 4);
9655 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9656}
9657
9658static inline void
9659tr_buffer_free(struct tr_buffer *buffer)
9660{
9661 if (buffer->buf) {
9662 SIZED_FREE_N(buffer->buf, buffer->capa);
9663 }
9664}
9665
9666struct tr_pair {
9667 VALUE search;
9668 VALUE replace;
9669};
9670
9672 struct tr_pair *pairs;
9673 size_t index;
9674 rb_encoding *enc;
9675 int cr;
9676};
9677
9678static int
9679tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9680{
9681 struct tr_trans_pairs_coerce_args *args = (struct tr_trans_pairs_coerce_args *)_args;
9682 struct tr_pair *pair = &args->pairs[args->index];
9683 args->index++;
9684
9685 VALUE search = (VALUE)key;
9686 VALUE replace = (VALUE)value;
9687 StringValue(search);
9688 StringValue(replace);
9689
9690 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9691 rb_raise(rb_eArgError, "keys must be of size 1"); // TODO: better error message
9692 }
9693
9694 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9695 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9696
9697 pair->search = search;
9698 pair->replace = replace;
9699 return ST_CONTINUE;
9700}
9701
9702#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9703
9705 const unsigned char *s;
9706 const unsigned char *send;
9707
9708#ifdef HAVE_SIMD
9709 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9710 unsigned int needles_count;
9711#ifdef HAVE_SIMD_NEON
9712 uint64_t matches_bitmap;
9713#endif
9714#ifdef HAVE_SIMD_SSE2
9715 int matches_bitmap;
9716#endif
9717#endif
9718
9719 VALUE trans_table[256];
9720};
9721
9722static inline VALUE
9723tr_trans_pairs_search_basic(struct tr_trans_pairs_search *search)
9724{
9725 while (search->s < search->send) {
9726 VALUE repl = search->trans_table[*search->s];
9727 if (UNLIKELY(repl)) {
9728 return repl;
9729 }
9730
9731 search->s++;
9732 }
9733
9734 return 0;
9735}
9736
9737#ifdef HAVE_SIMD_SSE2
9738static inline VALUE
9739tr_trans_pairs_next_match_sse2(struct tr_trans_pairs_search *search)
9740{
9741 RUBY_ASSERT(search->matches_bitmap > 0);
9742 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9743
9744 RUBY_ASSERT(trailing_zeros < (sizeof(search->matches_bitmap) * CHAR_BIT));
9745 search->matches_bitmap >>= trailing_zeros;
9746 search->s += trailing_zeros;
9747
9748 RUBY_ASSERT(search->s <= search->send);
9749 return search->trans_table[*search->s];
9750}
9751
9752static inline VALUE
9753tr_trans_pairs_search_sse2(struct tr_trans_pairs_search *search)
9754{
9755 const unsigned int needles_count = search->needles_count;
9756 if (needles_count) {
9757 RBIMPL_ASSERT_OR_ASSUME(needles_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9758
9759 if (search->matches_bitmap) {
9760 return tr_trans_pairs_next_match_sse2(search);
9761 }
9762
9763 if ((size_t)(search->send - search->s) >= sizeof(__m128i)) {
9764 unsigned int i;
9765 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9766 for (i = 0; i < needles_count; i++) {
9767 masks[i] = _mm_set1_epi8(search->needles[i]);
9768 }
9769
9770 do {
9771 const __m128i bytes = _mm_loadu_si128((__m128i const *)search->s);
9772
9773 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9774 for (i = 0; i < needles_count; i++) {
9775 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9776 }
9777
9778 for (i = 1; i < needles_count; i++) {
9779 matches[0] = _mm_or_si128(matches[0], matches[i]);
9780 }
9781
9782 const int bitmap = _mm_movemask_epi8(matches[0]);
9783
9784 if (bitmap) {
9785 search->matches_bitmap = bitmap;
9786 return tr_trans_pairs_next_match_sse2(search);
9787 }
9788 search->s += sizeof(__m128i);
9789 } while ((size_t)(search->send - search->s) >= sizeof(__m128i));
9790 }
9791 }
9792 return tr_trans_pairs_search_basic(search);
9793}
9794
9795#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9796#endif
9797
9798#ifdef HAVE_SIMD_NEON
9799static inline VALUE
9800tr_trans_pairs_next_match_neon(struct tr_trans_pairs_search *search)
9801{
9802 RUBY_ASSERT(search->matches_bitmap > 0);
9803 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9804
9805 // uint64_t >>= 64 would be undefined behaviour
9806 RUBY_ASSERT(trailing_zeros < (sizeof(search->matches_bitmap) * CHAR_BIT));
9807 search->matches_bitmap >>= trailing_zeros;
9808 search->s += trailing_zeros / 4;
9809
9810 RUBY_ASSERT(search->s <= search->send);
9811 return search->trans_table[*search->s];
9812}
9813
9814static inline VALUE
9815tr_trans_pairs_search_neon(struct tr_trans_pairs_search *search)
9816{
9817 const unsigned int needles_count = search->needles_count;
9818 if (needles_count) {
9819 RBIMPL_ASSERT_OR_ASSUME(needles_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES);
9820
9821 if (search->matches_bitmap) {
9822 return tr_trans_pairs_next_match_neon(search);
9823 }
9824
9825 if ((size_t)(search->send - search->s) >= sizeof(uint8x16_t)) {
9826 unsigned int i;
9827 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9828 for (i = 0; i < needles_count; i++) {
9829 masks[i] = vdupq_n_u8(search->needles[i]);
9830 }
9831
9832 do {
9833 const uint8x16_t bytes = vld1q_u8(search->s);
9834
9835 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9836 for (i = 0; i < needles_count; i++) {
9837 matches[i] = vceqq_u8(bytes, masks[i]);
9838 }
9839
9840 for (i = 1; i < needles_count; i++) {
9841 matches[0] = vorrq_u8(matches[0], matches[i]);
9842 }
9843
9844 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9845 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9846
9847 if (bitmap) {
9848 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9849 return tr_trans_pairs_next_match_neon(search);
9850 }
9851 search->s += sizeof(uint8x16_t);
9852 } while ((size_t)(search->send - search->s) >= sizeof(uint8x16_t));
9853 }
9854 }
9855 return tr_trans_pairs_search_basic(search);
9856}
9857
9858#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9859#endif
9860
9861#ifndef tr_trans_pairs_search_impl
9862#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9863#endif
9864
9865static inline void
9866tr_trans_pairs_consume_match(struct tr_trans_pairs_search *search)
9867{
9868 search->s++;
9869#ifdef HAVE_SIMD
9870 search->matches_bitmap >>= 1;
9871#endif
9872}
9873
9874static VALUE
9875tr_trans_pairs(VALUE str, VALUE pairs_val)
9876{
9877 Check_Type(pairs_val, T_HASH);
9878 size_t pairs_count = RHASH_SIZE(pairs_val);
9879 mustnot_broken(str);
9880 rb_str_modify(str);
9881
9882 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0) return Qnil;
9883
9884 VALUE pairs_handle;
9885 struct tr_pair *pairs = ALLOCV_N(struct tr_pair, pairs_handle, pairs_count);
9886
9887 int cr = rb_enc_str_coderange(str);
9888 rb_encoding *enc = rb_str_enc_get(str);
9889
9890 struct tr_trans_pairs_coerce_args coerce_args = {
9891 .pairs = pairs,
9892 .enc = enc,
9893 .cr = cr,
9894 };
9895 rb_hash_foreach(pairs_val, tr_trans_pairs_coerce_i, (VALUE)&coerce_args);
9896 rb_encoding *e1 = coerce_args.enc;
9897
9898 /* Keys could be deleted from pairs_val during rb_hash_foreach when coercing
9899 * the keys/values, so we need to update pairs_count to the number of pairs we
9900 * were actually able to extract from pairs_val. */
9901 pairs_count = coerce_args.index;
9902
9903 VALUE hash = 0;
9904
9905 const unsigned char *sstart = (unsigned char *)RSTRING_PTR(str);
9906 rb_len_t str_len = RSTRING_LEN(str);
9907 int termlen = rb_enc_mbminlen(e1);
9908
9909 struct tr_buffer buffer;
9910 tr_buffer_init(&buffer, str_len);
9911 bool modify = false;
9912
9913 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9914
9915 struct tr_trans_pairs_search search = {
9916 .s = sstart,
9917 .send = sstart + str_len,
9918 };
9919
9920 for (size_t index = 0; index < pairs_count; index++) {
9921 struct tr_pair *pair = &pairs[index];
9922
9923 char *ptr = RSTRING_PTR(pair->search);
9924 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr, RSTRING_END(pair->search), e1);
9925
9926 const unsigned char first_byte = (unsigned char)*ptr;
9927
9928#ifdef HAVE_SIMD
9929 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9930 search.needles[index] = first_byte;
9931 search.needles_count++;
9932 }
9933#endif
9934
9935 if (rb_enc_codelen(codepoint, e1) == 1) {
9936 search.trans_table[first_byte] = pair->replace;
9937 }
9938 else {
9939 search.trans_table[first_byte] = Qundef;
9940 if (!hash) {
9941 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9942 }
9943 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9944 }
9945 }
9946
9947 const unsigned char *checkpoint = search.s;
9948 VALUE repl;
9949 while ((repl = tr_trans_pairs_search_impl(&search))) {
9950 int clen = 1;
9951
9952 if (UNLIKELY(repl == Qundef)) {
9953 unsigned int c = rb_enc_mbc_to_codepoint((char *)search.s, (char *)search.send, e1);
9954 clen = rb_enc_codelen(c, e1);
9955 repl = rb_hash_lookup2(hash, UINT2NUM(c), 0);
9956 if (!repl) {
9957 tr_trans_pairs_consume_match(&search);
9958 continue;
9959 }
9960 }
9962
9963 modify = true;
9964
9965 if (checkpoint < search.s) {
9966 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9967 }
9968 tr_buffer_append_str(&buffer, repl);
9969 checkpoint = search.s + clen;
9970 tr_trans_pairs_consume_match(&search);
9971
9972 if (cr == ENC_CODERANGE_7BIT && rb_enc_str_coderange(repl) != ENC_CODERANGE_7BIT) {
9974 }
9975 }
9976
9977 if (modify && checkpoint < search.s) {
9978 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9979 }
9980 }
9981 else {
9982 const unsigned char *s = sstart;
9983 const unsigned char *send = sstart + str_len;
9984
9985 hash = rb_obj_hide(rb_hash_new_capa(pairs_count));
9986
9987 for (size_t index = 0; index < pairs_count; index++) {
9988 struct tr_pair *pair = &pairs[index];
9989
9990 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search), RSTRING_END(pair->search), e1);
9991 rb_hash_aset(hash, UINT2NUM(codepoint), pair->replace);
9992 }
9993
9994 while (s < send) {
9995 bool may_modify = false;
9996
9997 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
9998 if (!MBCLEN_CHARFOUND_P(r)) {
9999 tr_buffer_free(&buffer);
10000 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
10001 }
10002 int clen = MBCLEN_CHARFOUND_LEN(r);
10003 unsigned int c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
10004 unsigned int c0 = c;
10005
10006 rb_len_t tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
10007
10008 VALUE replacement = rb_hash_lookup(hash, UINT2NUM(c));
10009 if (NIL_P(replacement)) {
10010 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
10011 c = c0;
10012 if (enc != e1) may_modify = true;
10013 }
10014 else {
10015 tlen = RSTRING_LEN(replacement);
10016 modify = true;
10017 }
10018
10019 if (NIL_P(replacement)) {
10020 tr_buffer_mbcput(&buffer, c, enc);
10021 }
10022 else {
10023 tr_buffer_append_str(&buffer, replacement);
10024 }
10025
10026 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
10027 modify = true;
10028 }
10029
10030 if (cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) {
10032 }
10033
10034 s += clen;
10035 }
10036 }
10037
10038 ALLOCV_END(pairs_handle);
10039
10040 if (!modify) {
10041 return Qnil;
10042 }
10043
10044 if (!STR_EMBED_P(str)) {
10045 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
10046 }
10047 tr_buffer_ensure_capa(&buffer, termlen);
10048 TERM_FILL((char *)buffer.ptr, termlen);
10049 RSTRING(str)->as.heap.ptr = (char *)buffer.buf;
10050 STR_SET_LEN(str, buffer.ptr - buffer.buf);
10051 STR_SET_NOEMBED(str);
10052 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
10053
10054 RB_GC_GUARD(hash);
10055
10056 if (cr != ENC_CODERANGE_BROKEN)
10057 ENC_CODERANGE_SET(str, cr);
10058 rb_enc_associate(str, e1);
10059 return str;
10060}
10061
10062/*
10063 * call-seq:
10064 * tr!(selector, replacements) -> self or nil
10065 * tr!(pairs) -> self or nil
10066 *
10067 * Like String#tr, except:
10068 *
10069 * - Performs substitutions in +self+ (not in a copy of +self+).
10070 * - Returns +self+ if any modifications were made, +nil+ otherwise.
10071 *
10072 * Related: {Modifying}[rdoc-ref:String@Modifying].
10073 */
10074
10075static VALUE
10076rb_str_tr_bang(int argc, VALUE *argv, VALUE str)
10077{
10078 rb_check_arity(argc, 1, 2);
10079
10080 if (argc == 1) {
10081 VALUE pairs = argv[0];
10082 return tr_trans_pairs(str, pairs);
10083 }
10084
10085 VALUE src = argv[0], repl = argv[1];
10086 return tr_trans(str, src, repl, 0);
10087}
10088
10089
10090/*
10091 * call-seq:
10092 * tr(pairs) -> new_string
10093 * tr(selector, replacements) -> new_string
10094 *
10095 * With hash argument +pairs+ given,
10096 * returns a copy of +self+ with some codepoints replaced:
10097 *
10098 * - Each key in +pairs+ is a string contains a single codepoint.
10099 * - Each value in +pairs+ is a string of any length (even length zero).
10100 *
10101 * Each codepoint in +self+ is examined;
10102 * when the codepoint in +self+ matches a key codepoint in +pairs+,
10103 * the string value for that key replaces the codepoint in +self+.
10104 *
10105 * Examples:
10106 *
10107 * h = {'h' => 'H', 'e' => 'er', 'l' => '', 'o' => 'o!'}
10108 * 'hello'.tr(h) # => "Hero!"
10109 *
10110 * With string arguments +selector+ and +replacements+ given,
10111 * returns a copy of +self+
10112 * with each character specified by string +selector+ translated to the
10113 * corresponding character in string +replacements+.
10114 * The correspondence is _positional_:
10115 *
10116 * - Each occurrence of the first character specified by +selector+
10117 * is translated to the first character in +replacements+.
10118 * - Each occurrence of the second character specified by +selector+
10119 * is translated to the second character in +replacements+.
10120 * - And so on.
10121 *
10122 * Example:
10123 *
10124 * 'hello'.tr('el', 'ip') #=> "hippo"
10125 *
10126 * If +replacements+ is shorter than +selector+,
10127 * it is implicitly padded with its own last character:
10128 *
10129 * 'hello'.tr('aeiou', '-') # => "h-ll-"
10130 * 'hello'.tr('aeiou', 'AA-') # => "hAll-"
10131 *
10132 * Arguments +selector+ and +replacements+ must be valid character selectors
10133 * (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
10134 * and may use any of its valid forms, including negation, ranges, and escapes:
10135 *
10136 * 'hello'.tr('^aeiou', '-') # => "-e--o" # Negation.
10137 * 'ibm'.tr('b-z', 'a-z') # => "hal" # Range.
10138 * 'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret.
10139 * 'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen.
10140 * 'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash.
10141 *
10142 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10143 */
10144
10145static VALUE
10146rb_str_tr(int argc, VALUE *argv, VALUE str)
10147{
10148 rb_check_arity(argc, 1, 2);
10149
10150 str = str_duplicate(rb_cString, str);
10151
10152 if (argc == 1) {
10153 VALUE pairs = argv[0];
10154 VALUE result = tr_trans_pairs(str, pairs);
10155 if (NIL_P(result)) result = str;
10156 return str;
10157 }
10158
10159 VALUE src = argv[0], repl = argv[1];
10160 tr_trans(str, src, repl, 0);
10161 return str;
10162}
10163
10164#define TR_TABLE_MAX (UCHAR_MAX+1)
10165#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10166static void
10167tr_setup_table(VALUE str, char stable[TR_TABLE_SIZE], int first,
10168 VALUE *tablep, VALUE *ctablep, rb_encoding *enc)
10169{
10170 const unsigned int errc = -1;
10171 char buf[TR_TABLE_MAX];
10172 struct tr tr;
10173 unsigned int c;
10174 VALUE table = 0, ptable = 0;
10175 int i, l, cflag = 0;
10176
10177 tr.p = RSTRING_PTR(str); tr.pend = tr.p + RSTRING_LEN(str);
10178 tr.gen = tr.now = tr.max = 0;
10179
10180 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(tr.p, tr.pend, &l, enc) == '^') {
10181 cflag = 1;
10182 tr.p += l;
10183 }
10184 if (first) {
10185 for (i=0; i<TR_TABLE_MAX; i++) {
10186 stable[i] = 1;
10187 }
10188 stable[TR_TABLE_MAX] = cflag;
10189 }
10190 else if (stable[TR_TABLE_MAX] && !cflag) {
10191 stable[TR_TABLE_MAX] = 0;
10192 }
10193 for (i=0; i<TR_TABLE_MAX; i++) {
10194 buf[i] = cflag;
10195 }
10196
10197 while ((c = trnext(&tr, enc)) != errc) {
10198 if (c < TR_TABLE_MAX) {
10199 buf[(unsigned char)c] = !cflag;
10200 }
10201 else {
10202 VALUE key = UINT2NUM(c);
10203
10204 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10205 if (cflag) {
10206 ptable = *ctablep;
10207 table = ptable ? ptable : rb_hash_new();
10208 *ctablep = table;
10209 }
10210 else {
10211 table = rb_hash_new();
10212 ptable = *tablep;
10213 *tablep = table;
10214 }
10215 }
10216 if (table && (!ptable || (cflag ^ !NIL_P(rb_hash_aref(ptable, key))))) {
10217 rb_hash_aset(table, key, Qtrue);
10218 }
10219 }
10220 }
10221 for (i=0; i<TR_TABLE_MAX; i++) {
10222 stable[i] = stable[i] && buf[i];
10223 }
10224 if (!table && !cflag) {
10225 *tablep = 0;
10226 }
10227}
10228
10229
10230static int
10231tr_find(unsigned int c, const char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
10232{
10233 if (c < TR_TABLE_MAX) {
10234 return table[c] != 0;
10235 }
10236 else {
10237 VALUE v = UINT2NUM(c);
10238
10239 if (del) {
10240 if (!NIL_P(rb_hash_lookup(del, v)) &&
10241 (!nodel || NIL_P(rb_hash_lookup(nodel, v)))) {
10242 return TRUE;
10243 }
10244 }
10245 else if (nodel && !NIL_P(rb_hash_lookup(nodel, v))) {
10246 return FALSE;
10247 }
10248 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10249 }
10250}
10251
10252/*
10253 * call-seq:
10254 * delete!(*selectors) -> self or nil
10255 *
10256 * Like String#delete, but modifies +self+ in place;
10257 * returns +self+ if any characters were deleted, +nil+ otherwise.
10258 *
10259 * Related: see {Modifying}[rdoc-ref:String@Modifying].
10260 */
10261
10262static VALUE
10263rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
10264{
10265 char squeez[TR_TABLE_SIZE];
10266 rb_encoding *enc = 0;
10267 char *s, *send, *t;
10268 VALUE del = 0, nodel = 0;
10269 int modify = 0;
10270 int i, ascompat, cr;
10271
10272 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
10274 for (i=0; i<argc; i++) {
10275 VALUE s = argv[i];
10276
10277 StringValue(s);
10278 enc = rb_enc_check(str, s);
10279 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10280 }
10281
10282 str_modify_keep_cr(str);
10283 ascompat = rb_enc_asciicompat(enc);
10284 s = t = RSTRING_PTR(str);
10285 send = RSTRING_END(str);
10286 cr = ascompat ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
10287 while (s < send) {
10288 unsigned int c;
10289 int clen;
10290
10291 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
10292 if (squeez[c]) {
10293 modify = 1;
10294 }
10295 else {
10296 if (t != s) *t = c;
10297 t++;
10298 }
10299 s++;
10300 }
10301 else {
10302 c = rb_enc_codepoint_len(s, send, &clen, enc);
10303
10304 if (tr_find(c, squeez, del, nodel)) {
10305 modify = 1;
10306 }
10307 else {
10308 if (t != s) rb_enc_mbcput(c, t, enc);
10309 t += clen;
10311 }
10312 s += clen;
10313 }
10314 }
10315 TERM_FILL(t, TERM_LEN(str));
10316 STR_SET_LEN(str, t - RSTRING_PTR(str));
10317 ENC_CODERANGE_SET(str, cr);
10318
10319 if (modify) return str;
10320 return Qnil;
10321}
10322
10323
10324/*
10325 * call-seq:
10326 * delete(*selectors) -> new_string
10327 *
10328 * :include: doc/string/delete.rdoc
10329 *
10330 */
10331
10332static VALUE
10333rb_str_delete(int argc, VALUE *argv, VALUE str)
10334{
10335 str = str_duplicate(rb_cString, str);
10336 rb_str_delete_bang(argc, argv, str);
10337 return str;
10338}
10339
10340
10341/*
10342 * call-seq:
10343 * squeeze!(*selectors) -> self or nil
10344 *
10345 * Like String#squeeze, except that:
10346 *
10347 * - Characters are squeezed in +self+ (not in a copy of +self+).
10348 * - Returns +self+ if any changes are made, +nil+ otherwise.
10349 *
10350 * Related: See {Modifying}[rdoc-ref:String@Modifying].
10351 */
10352
10353static VALUE
10354rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
10355{
10356 char squeez[TR_TABLE_SIZE];
10357 rb_encoding *enc = 0;
10358 VALUE del = 0, nodel = 0;
10359 unsigned char *s, *send, *t;
10360 int i, modify = 0;
10361 int ascompat, singlebyte = single_byte_optimizable(str);
10362 unsigned int save;
10363
10364 if (argc == 0) {
10365 enc = STR_ENC_GET(str);
10366 }
10367 else {
10368 for (i=0; i<argc; i++) {
10369 VALUE s = argv[i];
10370
10371 StringValue(s);
10372 enc = rb_enc_check(str, s);
10373 if (singlebyte && !single_byte_optimizable(s))
10374 singlebyte = 0;
10375 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10376 }
10377 }
10378
10379 str_modify_keep_cr(str);
10380 s = t = (unsigned char *)RSTRING_PTR(str);
10381 if (!s || RSTRING_LEN(str) == 0) return Qnil;
10382 send = (unsigned char *)RSTRING_END(str);
10383 save = -1;
10384 ascompat = rb_enc_asciicompat(enc);
10385
10386 if (singlebyte) {
10387 while (s < send) {
10388 unsigned int c = *s++;
10389 if (c != save || (argc > 0 && !squeez[c])) {
10390 *t++ = save = c;
10391 }
10392 }
10393 }
10394 else {
10395 while (s < send) {
10396 unsigned int c;
10397 int clen;
10398
10399 if (ascompat && (c = *s) < 0x80) {
10400 if (c != save || (argc > 0 && !squeez[c])) {
10401 *t++ = save = c;
10402 }
10403 s++;
10404 }
10405 else {
10406 c = rb_enc_codepoint_len((char *)s, (char *)send, &clen, enc);
10407
10408 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10409 if (t != s) rb_enc_mbcput(c, t, enc);
10410 save = c;
10411 t += clen;
10412 }
10413 s += clen;
10414 }
10415 }
10416 }
10417
10418 TERM_FILL((char *)t, TERM_LEN(str));
10419 if ((char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10420 STR_SET_LEN(str, (char *)t - RSTRING_PTR(str));
10421 modify = 1;
10422 }
10423
10424 if (modify) return str;
10425 return Qnil;
10426}
10427
10428
10429/*
10430 * call-seq:
10431 * squeeze(*selectors) -> new_string
10432 *
10433 * :include: doc/string/squeeze.rdoc
10434 *
10435 */
10436
10437static VALUE
10438rb_str_squeeze(int argc, VALUE *argv, VALUE str)
10439{
10440 str = str_duplicate(rb_cString, str);
10441 rb_str_squeeze_bang(argc, argv, str);
10442 return str;
10443}
10444
10445
10446/*
10447 * call-seq:
10448 * tr_s!(selector, replacements) -> self or nil
10449 *
10450 * Like String#tr_s, except:
10451 *
10452 * - Modifies +self+ in place (not a copy of +self+).
10453 * - Returns +self+ if any changes were made, +nil+ otherwise.
10454 *
10455 * Related: {Modifying}[rdoc-ref:String@Modifying].
10456 */
10457
10458static VALUE
10459rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
10460{
10461 return tr_trans(str, src, repl, 1);
10462}
10463
10464
10465/*
10466 * call-seq:
10467 * tr_s(selector, replacements) -> new_string
10468 *
10469 * Like String#tr, except:
10470 *
10471 * - Also squeezes the modified portions of the translated string;
10472 * see String#squeeze.
10473 * - Returns the translated and squeezed string.
10474 *
10475 * Examples:
10476 *
10477 * 'hello'.tr_s('l', 'r') #=> "hero"
10478 * 'hello'.tr_s('el', '-') #=> "h-o"
10479 * 'hello'.tr_s('el', 'hx') #=> "hhxo"
10480 *
10481 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10482 *
10483 */
10484
10485static VALUE
10486rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
10487{
10488 str = str_duplicate(rb_cString, str);
10489 tr_trans(str, src, repl, 1);
10490 return str;
10491}
10492
10493
10494/*
10495 * call-seq:
10496 * count(*selectors) -> integer
10497 *
10498 * :include: doc/string/count.rdoc
10499 */
10500
10501static VALUE
10502rb_str_count(int argc, VALUE *argv, VALUE str)
10503{
10504 char table[TR_TABLE_SIZE];
10505 rb_encoding *enc = 0;
10506 VALUE del = 0, nodel = 0, tstr;
10507 const char *s, *send;
10508 int i;
10509 int ascompat;
10510 size_t n = 0;
10511
10513
10514 tstr = argv[0];
10515 StringValue(tstr);
10516 enc = rb_enc_check(str, tstr);
10517 if (argc == 1) {
10518 const char *ptstr;
10519 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10520 (ptstr = RSTRING_PTR(tstr),
10521 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
10522 !is_broken_string(str)) {
10523 int clen;
10524 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10525
10526 s = RSTRING_PTR(str);
10527 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10528 send = RSTRING_END(str);
10529 while (s < send) {
10530 if (*(unsigned char*)s++ == c) n++;
10531 }
10532 return SIZET2NUM(n);
10533 }
10534 }
10535
10536 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10537 for (i=1; i<argc; i++) {
10538 tstr = argv[i];
10539 StringValue(tstr);
10540 enc = rb_enc_check(str, tstr);
10541 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10542 }
10543
10544 s = RSTRING_PTR(str);
10545 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
10546 send = RSTRING_END(str);
10547 ascompat = rb_enc_asciicompat(enc);
10548 while (s < send) {
10549 unsigned int c;
10550
10551 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
10552 if (table[c]) {
10553 n++;
10554 }
10555 s++;
10556 }
10557 else {
10558 int clen;
10559 c = rb_enc_codepoint_len(s, send, &clen, enc);
10560 if (tr_find(c, table, del, nodel)) {
10561 n++;
10562 }
10563 s += clen;
10564 }
10565 }
10566
10567 return SIZET2NUM(n);
10568}
10569
10570static VALUE
10571rb_fs_check(VALUE val)
10572{
10573 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING) && !RB_TYPE_P(val, T_REGEXP)) {
10574 val = rb_check_string_type(val);
10575 if (NIL_P(val)) return 0;
10576 }
10577 return val;
10578}
10579
10580static const char isspacetable[256] = {
10581 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10583 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10584 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10585 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10588 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10590 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10592 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10594 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10595 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10596 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10597};
10598
10599#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10600
10601static rb_len_t
10602split_string(VALUE result, VALUE str, rb_len_t beg, rb_len_t len, rb_len_t empty_count)
10603{
10604 if (empty_count >= 0 && len == 0) {
10605 return empty_count + 1;
10606 }
10607 if (empty_count > 0) {
10608 /* make different substrings */
10609 if (result) {
10610 do {
10611 rb_ary_push(result, str_new_empty_String(str));
10612 } while (--empty_count > 0);
10613 }
10614 else {
10615 do {
10616 rb_yield(str_new_empty_String(str));
10617 } while (--empty_count > 0);
10618 }
10619 }
10620 str = rb_str_subseq(str, beg, len);
10621 if (result) {
10622 rb_ary_push(result, str);
10623 }
10624 else {
10625 rb_yield(str);
10626 }
10627 return empty_count;
10628}
10629
10630typedef enum {
10631 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10632} split_type_t;
10633
10634static split_type_t
10635literal_split_pattern(VALUE spat, split_type_t default_type)
10636{
10637 rb_encoding *enc = STR_ENC_GET(spat);
10638 const char *ptr;
10639 rb_len_t len;
10640 RSTRING_GETMEM(spat, ptr, len);
10641 if (len == 0) {
10642 /* Special case - split into chars */
10643 return SPLIT_TYPE_CHARS;
10644 }
10645 else if (rb_enc_asciicompat(enc)) {
10646 if (len == 1 && ptr[0] == ' ') {
10647 return SPLIT_TYPE_AWK;
10648 }
10649 }
10650 else {
10651 int l;
10652 if (rb_enc_ascget(ptr, ptr + len, &l, enc) == ' ' && len == l) {
10653 return SPLIT_TYPE_AWK;
10654 }
10655 }
10656 return default_type;
10657}
10658
10659/*
10660 * call-seq:
10661 * split(field_sep = $;, limit = 0) -> array_of_substrings
10662 * split(field_sep = $;, limit = 0) {|substring| ... } -> self
10663 *
10664 * :include: doc/string/split.rdoc
10665 *
10666 */
10667
10668static VALUE
10669rb_str_split_m(int argc, VALUE *argv, VALUE str)
10670{
10671 rb_encoding *enc;
10672 VALUE spat;
10673 VALUE limit;
10674 split_type_t split_type;
10675 rb_len_t beg, end, i = 0, empty_count = -1;
10676 int lim = 0;
10677 VALUE result, tmp;
10678
10679 result = rb_block_given_p() ? Qfalse : Qnil;
10680 if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
10681 lim = NUM2INT(limit);
10682 if (lim <= 0) limit = Qnil;
10683 else if (lim == 1) {
10684 if (RSTRING_LEN(str) == 0)
10685 return result ? rb_ary_new2(0) : str;
10686 tmp = str_duplicate(rb_cString, str);
10687 if (!result) {
10688 rb_yield(tmp);
10689 return str;
10690 }
10691 return rb_ary_new3(1, tmp);
10692 }
10693 i = 1;
10694 }
10695 if (NIL_P(limit) && !lim) empty_count = 0;
10696
10697 enc = STR_ENC_GET(str);
10698 split_type = SPLIT_TYPE_REGEXP;
10699 if (!NIL_P(spat)) {
10700 spat = get_pat_quoted(spat, 0);
10701 }
10702 else if (NIL_P(spat = rb_fs)) {
10703 split_type = SPLIT_TYPE_AWK;
10704 }
10705 else if (!(spat = rb_fs_check(spat))) {
10706 rb_raise(rb_eTypeError, "value of $; must be String or Regexp");
10707 }
10708 else {
10709 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$; is set to non-nil value");
10710 }
10711 if (split_type != SPLIT_TYPE_AWK) {
10712 switch (BUILTIN_TYPE(spat)) {
10713 case T_REGEXP:
10714 rb_reg_options(spat); /* check if uninitialized */
10715 tmp = RREGEXP_SRC(spat);
10716 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10717 if (split_type == SPLIT_TYPE_AWK) {
10718 spat = tmp;
10719 split_type = SPLIT_TYPE_STRING;
10720 }
10721 break;
10722
10723 case T_STRING:
10724 mustnot_broken(spat);
10725 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10726 break;
10727
10728 default:
10730 }
10731 }
10732
10733#define SPLIT_STR(beg, len) ( \
10734 empty_count = split_string(result, str, beg, len, empty_count), \
10735 str_mod_check(str, str_start, str_len))
10736
10737 beg = 0;
10738 const char *ptr = RSTRING_PTR(str);
10739 const char *const str_start = ptr;
10740 const rb_len_t str_len = RSTRING_LEN(str);
10741 const char *const eptr = str_start + str_len;
10742 if (split_type == SPLIT_TYPE_AWK) {
10743 const char *bptr = ptr;
10744 int skip = 1;
10745 unsigned int c;
10746
10747 if (result) result = rb_ary_new();
10748 end = beg;
10749 if (is_ascii_string(str)) {
10750 while (ptr < eptr) {
10751 c = (unsigned char)*ptr++;
10752 if (skip) {
10753 if (ascii_isspace(c)) {
10754 beg = ptr - bptr;
10755 }
10756 else {
10757 end = ptr - bptr;
10758 skip = 0;
10759 if (!NIL_P(limit) && lim <= i) break;
10760 }
10761 }
10762 else if (ascii_isspace(c)) {
10763 SPLIT_STR(beg, end-beg);
10764 skip = 1;
10765 beg = ptr - bptr;
10766 if (!NIL_P(limit)) ++i;
10767 }
10768 else {
10769 end = ptr - bptr;
10770 }
10771 }
10772 }
10773 else {
10774 while (ptr < eptr) {
10775 int n;
10776
10777 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10778 ptr += n;
10779 if (skip) {
10780 if (rb_isspace(c)) {
10781 beg = ptr - bptr;
10782 }
10783 else {
10784 end = ptr - bptr;
10785 skip = 0;
10786 if (!NIL_P(limit) && lim <= i) break;
10787 }
10788 }
10789 else if (rb_isspace(c)) {
10790 SPLIT_STR(beg, end-beg);
10791 skip = 1;
10792 beg = ptr - bptr;
10793 if (!NIL_P(limit)) ++i;
10794 }
10795 else {
10796 end = ptr - bptr;
10797 }
10798 }
10799 }
10800 }
10801 else if (split_type == SPLIT_TYPE_STRING) {
10802 const char *substr_start = ptr;
10803 const char *sptr = RSTRING_PTR(spat);
10804 rb_len_t slen = RSTRING_LEN(spat);
10805
10806 if (result) result = rb_ary_new();
10807 mustnot_broken(str);
10808 enc = rb_enc_check(str, spat);
10809 while (ptr < eptr &&
10810 (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10811 /* Check we are at the start of a char */
10812 const char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc);
10813 if (t != ptr + end) {
10814 ptr = t;
10815 continue;
10816 }
10817 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10818 str_mod_check(spat, sptr, slen);
10819 ptr += end + slen;
10820 substr_start = ptr;
10821 if (!NIL_P(limit) && lim <= ++i) break;
10822 }
10823 beg = ptr - str_start;
10824 }
10825 else if (split_type == SPLIT_TYPE_CHARS) {
10826 int n;
10827
10828 if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
10829 mustnot_broken(str);
10830 enc = rb_enc_get(str);
10831 while (ptr < eptr &&
10832 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10833 SPLIT_STR(ptr - str_start, n);
10834 ptr += n;
10835 if (!NIL_P(limit) && lim <= ++i) break;
10836 }
10837 beg = ptr - str_start;
10838 }
10839 else {
10840 if (result) result = rb_ary_new();
10841 rb_len_t len = RSTRING_LEN(str);
10842 rb_len_t start = beg;
10843 int idx;
10844 int last_null = 0;
10845 VALUE match = 0;
10846 /* Search the frozen copy made by the first match, so that every
10847 * following match does not copy an embedded str again. */
10848 VALUE search = str;
10849
10850 for (; rb_reg_search(spat, search, start, 0) >= 0;
10851 (match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
10852 match = rb_backref_get();
10853 search = RMATCH(match)->str;
10854 if (!result) rb_match_busy(match);
10855 end = RMATCH_BEG(match, 0);
10856 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10857 if (!ptr) {
10858 SPLIT_STR(0, 0);
10859 break;
10860 }
10861 else if (last_null == 1) {
10862 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10863 beg = start;
10864 }
10865 else {
10866 if (start == len)
10867 start++;
10868 else
10869 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10870 last_null = 1;
10871 continue;
10872 }
10873 }
10874 else {
10875 SPLIT_STR(beg, end-beg);
10876 beg = start = RMATCH_END(match, 0);
10877 }
10878 last_null = 0;
10879
10880 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10881 if (RMATCH_BEG(match, idx) == -1) continue;
10882 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10883 }
10884 if (!NIL_P(limit) && lim <= ++i) break;
10885 }
10886 if (match) rb_match_unbusy(match);
10887 }
10888 if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10889 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10890 }
10891
10892 return result ? result : str;
10893}
10894
10895VALUE
10896rb_str_split(VALUE str, const char *sep0)
10897{
10898 VALUE sep;
10899
10900 StringValue(str);
10901 sep = rb_str_new_cstr(sep0);
10902 return rb_str_split_m(1, &sep, str);
10903}
10904
10905#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10906
10907static inline int
10908enumerator_element(VALUE ary, VALUE e)
10909{
10910 if (ary) {
10911 rb_ary_push(ary, e);
10912 return 0;
10913 }
10914 else {
10915 rb_yield(e);
10916 return 1;
10917 }
10918}
10919
10920#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10921
10922static const char *
10923chomp_newline(const char *p, const char *e, rb_encoding *enc)
10924{
10925 const char *prev = rb_enc_prev_char(p, e, e, enc);
10926 if (rb_enc_is_newline(prev, e, enc)) {
10927 e = prev;
10928 prev = rb_enc_prev_char(p, e, e, enc);
10929 if (prev && rb_enc_ascget(prev, e, NULL, enc) == '\r')
10930 e = prev;
10931 }
10932 return e;
10933}
10934
10935static VALUE
10936get_rs(void)
10937{
10938 VALUE rs = rb_rs;
10939 if (!NIL_P(rs) &&
10940 (!RB_TYPE_P(rs, T_STRING) ||
10941 RSTRING_LEN(rs) != 1 ||
10942 RSTRING_PTR(rs)[0] != '\n')) {
10943 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$/ is set to non-default value");
10944 }
10945 return rs;
10946}
10947
10948#define rb_rs get_rs()
10949
10950static VALUE
10951rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
10952{
10953 rb_encoding *enc;
10954 VALUE line, rs, orig = str, opts = Qnil, chomp = Qfalse;
10955 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10956 rb_len_t pos, rslen;
10957 int rsnewline = 0;
10958
10959 if (rb_scan_args(argc, argv, "01:", &rs, &opts) == 0)
10960 rs = rb_rs;
10961 if (!NIL_P(opts)) {
10962 static ID keywords[1];
10963 if (!keywords[0]) {
10964 keywords[0] = rb_intern_const("chomp");
10965 }
10966 rb_get_kwargs(opts, keywords, 0, 1, &chomp);
10967 chomp = (!UNDEF_P(chomp) && RTEST(chomp));
10968 }
10969
10970 if (NIL_P(rs)) {
10971 if (!ENUM_ELEM(ary, str)) {
10972 return ary;
10973 }
10974 else {
10975 return orig;
10976 }
10977 }
10978
10979 if (!RSTRING_LEN(str)) goto end;
10980 str = rb_str_new_frozen(str);
10981 const char *const ptr = subptr = RSTRING_PTR(str);
10982 const rb_len_t len = RSTRING_LEN(str);
10983 pend = RSTRING_END(str);
10984 StringValue(rs);
10985 rslen = RSTRING_LEN(rs);
10986
10987 if (rs == rb_default_rs)
10988 enc = rb_enc_get(str);
10989 else
10990 enc = rb_enc_check(str, rs);
10991
10992 if (rslen == 0) {
10993 /* paragraph mode */
10994 int n;
10995 const char *eol = NULL;
10996 subend = subptr;
10997 while (subend < pend) {
10998 rb_len_t chomp_rslen = 0;
10999 do {
11000 if (rb_enc_ascget(subend, pend, &n, enc) != '\r')
11001 n = 0;
11002 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
11003 if (rb_enc_is_newline(subend + n, pend, enc)) {
11004 if (eol == subend) break;
11005 subend += rslen;
11006 if (subptr) {
11007 eol = subend;
11008 chomp_rslen = -rslen;
11009 }
11010 }
11011 else {
11012 if (!subptr) subptr = subend;
11013 subend += rslen;
11014 }
11015 rslen = 0;
11016 } while (subend < pend);
11017 if (!subptr) break;
11018 if (rslen == 0) chomp_rslen = 0;
11019 line = rb_str_subseq(str, subptr - ptr,
11020 subend - subptr + (chomp ? chomp_rslen : rslen));
11021 if (ENUM_ELEM(ary, line)) {
11022 str_mod_check(str, ptr, len);
11023 }
11024 subptr = eol = NULL;
11025 }
11026 goto end;
11027 }
11028 else {
11029 rsptr = RSTRING_PTR(rs);
11030 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
11031 rb_enc_is_newline(rsptr, rsptr + RSTRING_LEN(rs), enc)) {
11032 rsnewline = 1;
11033 }
11034 }
11035
11036 if ((rs == rb_default_rs) && !rb_enc_asciicompat(enc)) {
11037 rs = rb_str_new(rsptr, rslen);
11038 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
11039 rsptr = RSTRING_PTR(rs);
11040 rslen = RSTRING_LEN(rs);
11041 }
11042
11043 while (subptr < pend) {
11044 pos = rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
11045 if (pos < 0) break;
11046 hit = subptr + pos;
11047 adjusted = rb_enc_right_char_head(subptr, hit, pend, enc);
11048 if (hit != adjusted) {
11049 subptr = adjusted;
11050 continue;
11051 }
11052 subend = hit += rslen;
11053 if (chomp) {
11054 if (rsnewline) {
11055 subend = chomp_newline(subptr, subend, enc);
11056 }
11057 else {
11058 subend -= rslen;
11059 }
11060 }
11061 line = rb_str_subseq(str, subptr - ptr, subend - subptr);
11062 if (ENUM_ELEM(ary, line)) {
11063 str_mod_check(str, ptr, len);
11064 str_mod_check(rs, rsptr, rslen);
11065 }
11066 subptr = hit;
11067 }
11068
11069 if (subptr < pend) {
11070 if (chomp) {
11071 if (rsnewline) {
11072 pend = chomp_newline(subptr, pend, enc);
11073 }
11074 else if (pend - subptr >= rslen &&
11075 memcmp(pend - rslen, rsptr, rslen) == 0) {
11076 pend -= rslen;
11077 }
11078 }
11079 line = rb_str_subseq(str, subptr - ptr, pend - subptr);
11080 ENUM_ELEM(ary, line);
11081 RB_GC_GUARD(str);
11082 }
11083
11084 end:
11085 if (ary)
11086 return ary;
11087 else
11088 return orig;
11089}
11090
11091/*
11092 * call-seq:
11093 * each_line(record_separator = $/, chomp: false) {|substring| ... } -> self
11094 * each_line(record_separator = $/, chomp: false) -> enumerator
11095 *
11096 * :include: doc/string/each_line.rdoc
11097 *
11098 */
11099
11100static VALUE
11101rb_str_each_line(int argc, VALUE *argv, VALUE str)
11102{
11103 RETURN_SIZED_ENUMERATOR(str, argc, argv, 0);
11104 return rb_str_enumerate_lines(argc, argv, str, 0);
11105}
11106
11107/*
11108 * call-seq:
11109 * lines(record_separator = $/, chomp: false) -> array_of_strings
11110 *
11111 * Returns substrings ("lines") of +self+
11112 * according to the given arguments:
11113 *
11114 * s = <<~EOT
11115 * This is the first line.
11116 * This is line two.
11117 *
11118 * This is line four.
11119 * This is line five.
11120 * EOT
11121 *
11122 * With the default argument values:
11123 *
11124 * $/ # => "\n"
11125 * s.lines
11126 * # =>
11127 * ["This is the first line.\n",
11128 * "This is line two.\n",
11129 * "\n",
11130 * "This is line four.\n",
11131 * "This is line five.\n"]
11132 *
11133 * With a different +record_separator+:
11134 *
11135 * record_separator = ' is '
11136 * s.lines(record_separator)
11137 * # =>
11138 * ["This is ",
11139 * "the first line.\nThis is ",
11140 * "line two.\n\nThis is ",
11141 * "line four.\nThis is ",
11142 * "line five.\n"]
11143 *
11144 * With keyword argument +chomp+ as +true+,
11145 * removes the trailing newline from each line:
11146 *
11147 * s.lines(chomp: true)
11148 * # =>
11149 * ["This is the first line.",
11150 * "This is line two.",
11151 * "",
11152 * "This is line four.",
11153 * "This is line five."]
11154 *
11155 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
11156 */
11157
11158static VALUE
11159rb_str_lines(int argc, VALUE *argv, VALUE str)
11160{
11161 VALUE ary = WANTARRAY("lines", 0);
11162 return rb_str_enumerate_lines(argc, argv, str, ary);
11163}
11164
11165static VALUE
11166rb_str_each_byte_size(VALUE str, VALUE args, VALUE eobj)
11167{
11168 return LEN2NUM(RSTRING_LEN(str));
11169}
11170
11171static VALUE
11172rb_str_enumerate_bytes(VALUE str, VALUE ary)
11173{
11174 rb_len_t i;
11175
11176 for (i=0; i<RSTRING_LEN(str); i++) {
11177 ENUM_ELEM(ary, INT2FIX((unsigned char)RSTRING_PTR(str)[i]));
11178 }
11179 if (ary)
11180 return ary;
11181 else
11182 return str;
11183}
11184
11185/*
11186 * call-seq:
11187 * each_byte {|byte| ... } -> self
11188 * each_byte -> enumerator
11189 *
11190 * :include: doc/string/each_byte.rdoc
11191 *
11192 */
11193
11194static VALUE
11195rb_str_each_byte(VALUE str)
11196{
11197 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_byte_size);
11198 return rb_str_enumerate_bytes(str, 0);
11199}
11200
11201/*
11202 * call-seq:
11203 * bytes -> array_of_bytes
11204 *
11205 * :include: doc/string/bytes.rdoc
11206 *
11207 */
11208
11209static VALUE
11210rb_str_bytes(VALUE str)
11211{
11212 VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
11213 return rb_str_enumerate_bytes(str, ary);
11214}
11215
11216static VALUE
11217rb_str_each_char_size(VALUE str, VALUE args, VALUE eobj)
11218{
11219 return rb_str_length(str);
11220}
11221
11222static VALUE
11223rb_str_enumerate_chars(VALUE str, VALUE ary)
11224{
11225 VALUE orig = str;
11226 rb_len_t i, len, n;
11227 const char *ptr;
11228 rb_encoding *enc;
11229
11230 str = rb_str_new_frozen(str);
11231 ptr = RSTRING_PTR(str);
11232 len = RSTRING_LEN(str);
11233 enc = rb_enc_get(str);
11234
11236 for (i = 0; i < len; i += n) {
11237 n = rb_enc_fast_mbclen(ptr + i, ptr + len, enc);
11238 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
11239 }
11240 }
11241 else {
11242 for (i = 0; i < len; i += n) {
11243 n = rb_enc_mbclen(ptr + i, ptr + len, enc);
11244 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
11245 }
11246 }
11247 RB_GC_GUARD(str);
11248 if (ary)
11249 return ary;
11250 else
11251 return orig;
11252}
11253
11254/*
11255 * call-seq:
11256 * each_char {|char| ... } -> self
11257 * each_char -> enumerator
11258 *
11259 * :include: doc/string/each_char.rdoc
11260 *
11261 */
11262
11263static VALUE
11264rb_str_each_char(VALUE str)
11265{
11266 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
11267 return rb_str_enumerate_chars(str, 0);
11268}
11269
11270/*
11271 * call-seq:
11272 * chars -> array_of_characters
11273 *
11274 * :include: doc/string/chars.rdoc
11275 *
11276 */
11277
11278static VALUE
11279rb_str_chars(VALUE str)
11280{
11281 VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
11282 return rb_str_enumerate_chars(str, ary);
11283}
11284
11285static VALUE
11286rb_str_enumerate_codepoints(VALUE str, VALUE ary)
11287{
11288 VALUE orig = str;
11289 int n;
11290 unsigned int c;
11291 const char *ptr, *end;
11292 rb_encoding *enc;
11293 int enc_asciicompat;
11294
11295 if (single_byte_optimizable(str))
11296 return rb_str_enumerate_bytes(str, ary);
11297
11298 str = rb_str_new_frozen(str);
11299 ptr = RSTRING_PTR(str);
11300 end = RSTRING_END(str);
11301 enc = STR_ENC_GET(str);
11302 enc_asciicompat = rb_enc_asciicompat(enc);
11303
11304 while (ptr < end) {
11305 /* Fast path: ASCII byte in an ASCII-compatible encoding is its own codepoint;
11306 * skip rb_enc_codepoint_len and return the byte directly.
11307 */
11308 n = 1;
11309 c = (enc_asciicompat && ISASCII(*ptr)) ?
11310 (unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11311 ENUM_ELEM(ary, UINT2NUM(c));
11312 ptr += n;
11313 }
11314 RB_GC_GUARD(str);
11315 if (ary)
11316 return ary;
11317 else
11318 return orig;
11319}
11320
11321/*
11322 * call-seq:
11323 * each_codepoint {|codepoint| ... } -> self
11324 * each_codepoint -> enumerator
11325 *
11326 * :include: doc/string/each_codepoint.rdoc
11327 *
11328 */
11329
11330static VALUE
11331rb_str_each_codepoint(VALUE str)
11332{
11333 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
11334 return rb_str_enumerate_codepoints(str, 0);
11335}
11336
11337/*
11338 * call-seq:
11339 * codepoints -> array_of_integers
11340 *
11341 * :include: doc/string/codepoints.rdoc
11342 *
11343 */
11344
11345static VALUE
11346rb_str_codepoints(VALUE str)
11347{
11348 VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
11349 return rb_str_enumerate_codepoints(str, ary);
11350}
11351
11352static regex_t *
11353get_reg_grapheme_cluster(rb_encoding *enc)
11354{
11355 int encidx = rb_enc_to_index(enc);
11356
11357 const OnigUChar source_ascii[] = "\\X";
11358 const OnigUChar *source = source_ascii;
11359 size_t source_len = sizeof(source_ascii) - 1;
11360
11361 switch (encidx) {
11362#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11363#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11364#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11365#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11366#define CASE_UTF(e) \
11367 case ENCINDEX_UTF_##e: { \
11368 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11369 source = source_UTF_##e; \
11370 source_len = sizeof(source_UTF_##e); \
11371 break; \
11372 }
11373 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11374#undef CASE_UTF
11375#undef CHARS_16BE
11376#undef CHARS_16LE
11377#undef CHARS_32BE
11378#undef CHARS_32LE
11379 }
11380
11381 regex_t *reg_grapheme_cluster;
11382 OnigErrorInfo einfo;
11383 int r = onig_new(&reg_grapheme_cluster, source, source + source_len,
11384 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11385 if (r) {
11386 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11387 onig_error_code_to_str(message, r, &einfo);
11388 rb_fatal("cannot compile grapheme cluster regexp: %s", (char *)message);
11389 }
11390
11391 return reg_grapheme_cluster;
11392}
11393
11394static regex_t *
11395get_cached_reg_grapheme_cluster(rb_encoding *enc)
11396{
11397 int encidx = rb_enc_to_index(enc);
11398 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11399
11400 if (encidx == rb_utf8_encindex()) {
11401 if (!reg_grapheme_cluster_utf8) {
11402 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11403 }
11404
11405 return reg_grapheme_cluster_utf8;
11406 }
11407
11408 return NULL;
11409}
11410
11411static VALUE
11412rb_str_each_grapheme_cluster_size(VALUE str, VALUE args, VALUE eobj)
11413{
11414 size_t grapheme_cluster_count = 0;
11415 rb_encoding *enc = get_encoding(str);
11416 const char *ptr, *end;
11417
11418 if (!rb_enc_unicode_p(enc)) {
11419 return rb_str_length(str);
11420 }
11421
11422 bool cached_reg_grapheme_cluster = true;
11423 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11424 if (!reg_grapheme_cluster) {
11425 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11426 cached_reg_grapheme_cluster = false;
11427 }
11428
11429 ptr = RSTRING_PTR(str);
11430 end = RSTRING_END(str);
11431
11432 while (ptr < end) {
11433 OnigPosition len = onig_match(reg_grapheme_cluster,
11434 (const OnigUChar *)ptr, (const OnigUChar *)end,
11435 (const OnigUChar *)ptr, NULL, 0);
11436 if (len <= 0) break;
11437 grapheme_cluster_count++;
11438 ptr += len;
11439 }
11440
11441 if (!cached_reg_grapheme_cluster) {
11442 onig_free(reg_grapheme_cluster);
11443 }
11444
11445 return SIZET2NUM(grapheme_cluster_count);
11446}
11447
11448static VALUE
11449rb_str_enumerate_grapheme_clusters(VALUE str, VALUE ary)
11450{
11451 VALUE orig = str;
11452 rb_encoding *enc = get_encoding(str);
11453 const char *ptr0, *ptr, *end;
11454
11455 if (!rb_enc_unicode_p(enc)) {
11456 return rb_str_enumerate_chars(str, ary);
11457 }
11458
11459 if (!ary) str = rb_str_new_frozen(str);
11460
11461 bool cached_reg_grapheme_cluster = true;
11462 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11463 if (!reg_grapheme_cluster) {
11464 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11465 cached_reg_grapheme_cluster = false;
11466 }
11467
11468 ptr0 = ptr = RSTRING_PTR(str);
11469 end = RSTRING_END(str);
11470
11471 while (ptr < end) {
11472 OnigPosition len = onig_match(reg_grapheme_cluster,
11473 (const OnigUChar *)ptr, (const OnigUChar *)end,
11474 (const OnigUChar *)ptr, NULL, 0);
11475 if (len <= 0) break;
11476 ENUM_ELEM(ary, rb_str_subseq(str, ptr-ptr0, len));
11477 ptr += len;
11478 }
11479
11480 if (!cached_reg_grapheme_cluster) {
11481 onig_free(reg_grapheme_cluster);
11482 }
11483
11484 RB_GC_GUARD(str);
11485 if (ary)
11486 return ary;
11487 else
11488 return orig;
11489}
11490
11491/*
11492 * call-seq:
11493 * each_grapheme_cluster {|grapheme_cluster| ... } -> self
11494 * each_grapheme_cluster -> enumerator
11495 *
11496 * :include: doc/string/each_grapheme_cluster.rdoc
11497 *
11498 */
11499
11500static VALUE
11501rb_str_each_grapheme_cluster(VALUE str)
11502{
11503 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_grapheme_cluster_size);
11504 return rb_str_enumerate_grapheme_clusters(str, 0);
11505}
11506
11507/*
11508 * call-seq:
11509 * grapheme_clusters -> array_of_grapheme_clusters
11510 *
11511 * :include: doc/string/grapheme_clusters.rdoc
11512 *
11513 */
11514
11515static VALUE
11516rb_str_grapheme_clusters(VALUE str)
11517{
11518 VALUE ary = WANTARRAY("grapheme_clusters", rb_str_strlen(str));
11519 return rb_str_enumerate_grapheme_clusters(str, ary);
11520}
11521
11522static rb_len_t
11523chopped_length(VALUE str)
11524{
11525 rb_encoding *enc = STR_ENC_GET(str);
11526 const char *p, *p2, *beg, *end;
11527
11528 beg = RSTRING_PTR(str);
11529 end = beg + RSTRING_LEN(str);
11530 if (beg >= end) return 0;
11531 p = rb_enc_prev_char(beg, end, end, enc);
11532 if (!p) return 0;
11533 if (p > beg && rb_enc_ascget(p, end, 0, enc) == '\n') {
11534 p2 = rb_enc_prev_char(beg, p, end, enc);
11535 if (p2 && rb_enc_ascget(p2, end, 0, enc) == '\r') p = p2;
11536 }
11537 return p - beg;
11538}
11539
11540/*
11541 * call-seq:
11542 * chop! -> self or nil
11543 *
11544 * Like String#chop, except that:
11545 *
11546 * - Removes trailing characters from +self+ (not from a copy of +self+).
11547 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11548 *
11549 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11550 */
11551
11552static VALUE
11553rb_str_chop_bang(VALUE str)
11554{
11555 str_modify_keep_cr(str);
11556 if (RSTRING_LEN(str) > 0) {
11557 rb_len_t len;
11558 len = chopped_length(str);
11559 STR_SET_LEN(str, len);
11560 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11561 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11563 }
11564 return str;
11565 }
11566 return Qnil;
11567}
11568
11569
11570/*
11571 * call-seq:
11572 * chop -> new_string
11573 *
11574 * :include: doc/string/chop.rdoc
11575 *
11576 */
11577
11578static VALUE
11579rb_str_chop(VALUE str)
11580{
11581 return rb_str_subseq(str, 0, chopped_length(str));
11582}
11583
11584static rb_len_t
11585smart_chomp(VALUE str, const char *e, const char *p)
11586{
11587 rb_encoding *enc = rb_enc_get(str);
11588 if (rb_enc_mbminlen(enc) > 1) {
11589 /* a receiver shorter than one character has nothing to chomp */
11590 if (e - p < rb_enc_mbminlen(enc)) return e - p;
11591 const char *pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11592 if (rb_enc_is_newline(pp, e, enc)) {
11593 e = pp;
11594 }
11595 pp = e - rb_enc_mbminlen(enc);
11596 if (pp >= p) {
11597 pp = rb_enc_left_char_head(p, pp, e, enc);
11598 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11599 e = pp;
11600 }
11601 }
11602 }
11603 else {
11604 switch (*(e-1)) { /* not e[-1] to get rid of VC bug */
11605 case '\n':
11606 if (--e > p && *(e-1) == '\r') {
11607 --e;
11608 }
11609 break;
11610 case '\r':
11611 --e;
11612 break;
11613 }
11614 }
11615 return e - p;
11616}
11617
11618static rb_len_t
11619chompped_length(VALUE str, VALUE rs)
11620{
11621 rb_encoding *enc;
11622 int newline;
11623 const char *pp, *e, *rsptr;
11624 rb_len_t rslen;
11625 const char *const p = RSTRING_PTR(str);
11626 rb_len_t len = RSTRING_LEN(str);
11627
11628 if (len == 0) return 0;
11629 e = p + len;
11630 if (rs == rb_default_rs) {
11631 return smart_chomp(str, e, p);
11632 }
11633
11634 enc = rb_enc_get(str);
11635 RSTRING_GETMEM(rs, rsptr, rslen);
11636 if (rslen == 0) {
11637 if (rb_enc_mbminlen(enc) > 1) {
11638 while (e - p >= rb_enc_mbminlen(enc)) {
11639 pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
11640 if (!rb_enc_is_newline(pp, e, enc)) break;
11641 e = pp;
11642 pp -= rb_enc_mbminlen(enc);
11643 if (pp >= p) {
11644 pp = rb_enc_left_char_head(p, pp, e, enc);
11645 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
11646 e = pp;
11647 }
11648 }
11649 }
11650 }
11651 else {
11652 while (e > p && *(e-1) == '\n') {
11653 --e;
11654 if (e > p && *(e-1) == '\r')
11655 --e;
11656 }
11657 }
11658 return e - p;
11659 }
11660 if (rslen > len) return len;
11661
11662 enc = rb_enc_get(rs);
11663 newline = rsptr[rslen-1];
11664 if (rslen == rb_enc_mbminlen(enc)) {
11665 if (rslen == 1) {
11666 if (newline == '\n')
11667 return smart_chomp(str, e, p);
11668 }
11669 else {
11670 if (rb_enc_is_newline(rsptr, rsptr+rslen, enc))
11671 return smart_chomp(str, e, p);
11672 }
11673 }
11674
11675 enc = rb_enc_check(str, rs);
11676 if (is_broken_string(rs)) {
11677 return len;
11678 }
11679 pp = e - rslen;
11680 if (p[len-1] == newline &&
11681 (rslen <= 1 ||
11682 memcmp(rsptr, pp, rslen) == 0)) {
11683 if (at_char_boundary(p, pp, e, enc))
11684 return len - rslen;
11685 RB_GC_GUARD(rs);
11686 }
11687 return len;
11688}
11689
11695static VALUE
11696chomp_rs(int argc, const VALUE *argv)
11697{
11698 rb_check_arity(argc, 0, 1);
11699 if (argc > 0) {
11700 VALUE rs = argv[0];
11701 if (!NIL_P(rs)) StringValue(rs);
11702 return rs;
11703 }
11704 else {
11705 return rb_rs;
11706 }
11707}
11708
11709static VALUE
11710str_shrink(VALUE str, rb_len_t len)
11711{
11712 str_modify_keep_cr(str);
11713 STR_SET_LEN(str, len);
11714 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11715 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11717 }
11718 return str;
11719}
11720
11721VALUE
11722rb_str_chomp_string(VALUE str, VALUE rs)
11723{
11724 rb_len_t olen = RSTRING_LEN(str);
11725 rb_len_t len = chompped_length(str, rs);
11726 if (len >= olen) return Qnil;
11727 return str_shrink(str, len);
11728}
11729
11730/*
11731 * call-seq:
11732 * chomp!(line_sep = $/) -> self or nil
11733 *
11734 * Like String#chomp, except that:
11735 *
11736 * - Removes trailing characters from +self+ (not from a copy of +self+).
11737 * - Returns +self+ if any characters are removed, +nil+ otherwise.
11738 *
11739 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11740 */
11741
11742static VALUE
11743rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
11744{
11745 VALUE rs;
11746 str_modifiable(str);
11747 if (RSTRING_LEN(str) == 0 && argc < 2) return Qnil;
11748 rs = chomp_rs(argc, argv);
11749 if (NIL_P(rs)) return Qnil;
11750 return rb_str_chomp_string(str, rs);
11751}
11752
11753
11754/*
11755 * call-seq:
11756 * chomp(line_sep = $/) -> new_string
11757 *
11758 * :include: doc/string/chomp.rdoc
11759 *
11760 */
11761
11762static VALUE
11763rb_str_chomp(int argc, VALUE *argv, VALUE str)
11764{
11765 VALUE rs = chomp_rs(argc, argv);
11766 if (NIL_P(rs)) return str_duplicate(rb_cString, str);
11767 return rb_str_subseq(str, 0, chompped_length(str, rs));
11768}
11769
11770static void
11771tr_setup_table_multi(char table[TR_TABLE_SIZE], VALUE *tablep, VALUE *ctablep,
11772 VALUE str, int num_selectors, VALUE *selectors)
11773{
11774 int i;
11775
11776 for (i=0; i<num_selectors; i++) {
11777 VALUE selector = selectors[i];
11778 rb_encoding *enc;
11779
11780 StringValue(selector);
11781 enc = rb_enc_check(str, selector);
11782 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11783 }
11784}
11785
11786static rb_len_t
11787lstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11788{
11789 const char *const start = s;
11790
11791 if (!s || s >= e) return 0;
11792
11793 /* remove spaces at head */
11794 if (single_byte_optimizable(str)) {
11795 while (s < e && (*s == '\0' || ascii_isspace(*s))) s++;
11796 }
11797 else {
11798 while (s < e) {
11799 int n;
11800 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11801
11802 if (cc && !rb_isspace(cc)) break;
11803 s += n;
11804 }
11805 }
11806 return s - start;
11807}
11808
11809static rb_len_t
11810lstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11811 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11812{
11813 const char *const start = s;
11814
11815 if (!s || s >= e) return 0;
11816
11817 /* remove leading characters in the table */
11818 while (s < e) {
11819 int n;
11820 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11821
11822 if (!tr_find(cc, table, del, nodel)) break;
11823 s += n;
11824 }
11825 return s - start;
11826}
11827
11828/*
11829 * call-seq:
11830 * lstrip!(*selectors) -> self or nil
11831 *
11832 * Like String#lstrip, except that:
11833 *
11834 * - Performs stripping in +self+ (not in a copy of +self+).
11835 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11836 *
11837 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11838 */
11839
11840static VALUE
11841rb_str_lstrip_bang(int argc, VALUE *argv, VALUE str)
11842{
11843 rb_encoding *enc;
11844 char *start;
11845 rb_len_t olen, loffset;
11846
11847 str_modify_keep_cr(str);
11848 enc = STR_ENC_GET(str);
11849 RSTRING_GETMEM(str, start, olen);
11850 if (argc > 0) {
11851 char table[TR_TABLE_SIZE];
11852 VALUE del = 0, nodel = 0;
11853
11854 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11855
11856 /* the selector conversion may have modified str */
11857 str_modify_keep_cr(str);
11858 enc = STR_ENC_GET(str);
11859 RSTRING_GETMEM(str, start, olen);
11860
11861 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11862 }
11863 else {
11864 loffset = lstrip_offset(str, start, start+olen, enc);
11865 }
11866
11867 if (loffset > 0) {
11868 rb_len_t len = olen-loffset;
11869 memmove(start, start + loffset, len);
11870 STR_SET_LEN(str, len);
11871 TERM_FILL(start+len, rb_enc_mbminlen(enc));
11872 return str;
11873 }
11874 return Qnil;
11875}
11876
11877
11878/*
11879 * call-seq:
11880 * lstrip(*selectors) -> new_string
11881 *
11882 * Returns a copy of +self+ with leading whitespace removed;
11883 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
11884 *
11885 * whitespace = "\x00\t\n\v\f\r "
11886 * s = whitespace + 'abc' + whitespace
11887 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
11888 * s.lstrip
11889 * # => "abc\u0000\t\n\v\f\r "
11890 *
11891 * If +selectors+ are given, removes characters of +selectors+ from the beginning of +self+:
11892 *
11893 * s = "---abc+++"
11894 * s.lstrip("-") # => "abc+++"
11895 *
11896 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
11897 * and may use any of its valid forms, including negation, ranges, and escapes:
11898 *
11899 * "01234abc56789".lstrip("0-9") # "abc56789"
11900 * "01234abc56789".lstrip("0-9", "^4-6") # "4abc56789"
11901 *
11902 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
11903 */
11904
11905static VALUE
11906rb_str_lstrip(int argc, VALUE *argv, VALUE str)
11907{
11908 const char *start;
11909 rb_len_t len, loffset;
11910
11911 RSTRING_GETMEM(str, start, len);
11912 if (argc > 0) {
11913 char table[TR_TABLE_SIZE];
11914 VALUE del = 0, nodel = 0;
11915
11916 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11917
11918 /* the selector conversion may have modified str */
11919 RSTRING_GETMEM(str, start, len);
11920
11921 loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel);
11922 }
11923 else {
11924 loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
11925 }
11926 if (loffset <= 0) return str_duplicate(rb_cString, str);
11927 return rb_str_subseq(str, loffset, len - loffset);
11928}
11929
11930static rb_len_t
11931rstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
11932{
11933 const char *t;
11934
11935 rb_str_check_dummy_enc(enc);
11936 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11937 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11938 }
11939 if (!s || s >= e) return 0;
11940 t = e;
11941
11942 /* remove trailing spaces or '\0's */
11943 if (single_byte_optimizable(str)) {
11944 unsigned char c;
11945 while (s < t && ((c = *(t-1)) == '\0' || ascii_isspace(c))) t--;
11946 }
11947 else {
11948 const char *tp;
11949
11950 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11951 unsigned int c = rb_enc_codepoint(tp, e, enc);
11952 if (c && !rb_isspace(c)) break;
11953 t = tp;
11954 }
11955 }
11956 return e - t;
11957}
11958
11959static rb_len_t
11960rstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
11961 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
11962{
11963 const char *t, *tp;
11964
11965 rb_str_check_dummy_enc(enc);
11966 if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
11967 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
11968 }
11969 if (!s || s >= e) return 0;
11970 t = e;
11971
11972 /* remove trailing characters in the table */
11973 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11974 unsigned int c = rb_enc_codepoint(tp, e, enc);
11975 if (!tr_find(c, table, del, nodel)) break;
11976 t = tp;
11977 }
11978
11979 return e - t;
11980}
11981
11982/*
11983 * call-seq:
11984 * rstrip!(*selectors) -> self or nil
11985 *
11986 * Like String#rstrip, except that:
11987 *
11988 * - Performs stripping in +self+ (not in a copy of +self+).
11989 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
11990 *
11991 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11992 */
11993
11994static VALUE
11995rb_str_rstrip_bang(int argc, VALUE *argv, VALUE str)
11996{
11997 rb_encoding *enc;
11998 char *start;
11999 rb_len_t olen, roffset;
12000
12001 str_modify_keep_cr(str);
12002 enc = STR_ENC_GET(str);
12003 RSTRING_GETMEM(str, start, olen);
12004 if (argc > 0) {
12005 char table[TR_TABLE_SIZE];
12006 VALUE del = 0, nodel = 0;
12007
12008 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12009
12010 /* the selector conversion may have modified str */
12011 str_modify_keep_cr(str);
12012 enc = STR_ENC_GET(str);
12013 RSTRING_GETMEM(str, start, olen);
12014
12015 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12016 }
12017 else {
12018 roffset = rstrip_offset(str, start, start+olen, enc);
12019 }
12020 if (roffset > 0) {
12021 rb_len_t len = olen - roffset;
12022
12023 STR_SET_LEN(str, len);
12024 TERM_FILL(start+len, rb_enc_mbminlen(enc));
12025 return str;
12026 }
12027 return Qnil;
12028}
12029
12030
12031/*
12032 * call-seq:
12033 * rstrip(*selectors) -> new_string
12034 *
12035 * Returns a copy of +self+ with trailing whitespace removed;
12036 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
12037 *
12038 * whitespace = "\x00\t\n\v\f\r "
12039 * s = whitespace + 'abc' + whitespace
12040 * s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
12041 * s.rstrip # => "\u0000\t\n\v\f\r abc"
12042 *
12043 * If +selectors+ are given, removes characters of +selectors+ from the end of +self+:
12044 *
12045 * s = "---abc+++"
12046 * s.rstrip("+") # => "---abc"
12047 *
12048 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
12049 * and may use any of its valid forms, including negation, ranges, and escapes:
12050 *
12051 * "01234abc56789".rstrip("0-9") # "01234abc"
12052 * "01234abc56789".rstrip("0-9", "^4-6") # "01234abc56"
12053 *
12054 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
12055 */
12056
12057static VALUE
12058rb_str_rstrip(int argc, VALUE *argv, VALUE str)
12059{
12060 rb_encoding *enc;
12061 const char *start;
12062 rb_len_t olen, roffset;
12063
12064 enc = STR_ENC_GET(str);
12065 RSTRING_GETMEM(str, start, olen);
12066 if (argc > 0) {
12067 char table[TR_TABLE_SIZE];
12068 VALUE del = 0, nodel = 0;
12069
12070 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12071
12072 /* the selector conversion may have modified str */
12073 enc = STR_ENC_GET(str);
12074
12075 RSTRING_GETMEM(str, start, olen);
12076 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12077 }
12078 else {
12079 roffset = rstrip_offset(str, start, start+olen, enc);
12080 }
12081 if (roffset <= 0) return str_duplicate(rb_cString, str);
12082 return rb_str_subseq(str, 0, olen-roffset);
12083}
12084
12085
12086/*
12087 * call-seq:
12088 * strip!(*selectors) -> self or nil
12089 *
12090 * Like String#strip, except that:
12091 *
12092 * - Any modifications are made to +self+.
12093 * - Returns +self+ if any modification are made, +nil+ otherwise.
12094 *
12095 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12096 */
12097
12098static VALUE
12099rb_str_strip_bang(int argc, VALUE *argv, VALUE str)
12100{
12101 char *start;
12102 rb_len_t olen, loffset, roffset;
12103 rb_encoding *enc;
12104
12105 str_modify_keep_cr(str);
12106 enc = STR_ENC_GET(str);
12107 RSTRING_GETMEM(str, start, olen);
12108
12109 if (argc > 0) {
12110 char table[TR_TABLE_SIZE];
12111 VALUE del = 0, nodel = 0;
12112
12113 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12114
12115 /* the selector conversion may have modified str */
12116 str_modify_keep_cr(str);
12117 enc = STR_ENC_GET(str);
12118 RSTRING_GETMEM(str, start, olen);
12119
12120 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12121 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12122 }
12123 else {
12124 loffset = lstrip_offset(str, start, start+olen, enc);
12125 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12126 }
12127
12128 if (loffset > 0 || roffset > 0) {
12129 rb_len_t len = olen-roffset;
12130 if (loffset > 0) {
12131 len -= loffset;
12132 memmove(start, start + loffset, len);
12133 }
12134 STR_SET_LEN(str, len);
12135 TERM_FILL(start+len, rb_enc_mbminlen(enc));
12136 return str;
12137 }
12138 return Qnil;
12139}
12140
12141
12142/*
12143 * call-seq:
12144 * strip(*selectors) -> new_string
12145 *
12146 * Returns a copy of +self+ with leading and trailing whitespace removed;
12147 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
12148 *
12149 * whitespace = "\x00\t\n\v\f\r "
12150 * s = whitespace + 'abc' + whitespace
12151 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
12152 * s.strip # => "abc"
12153 *
12154 * If +selectors+ are given, removes characters of +selectors+ from both ends of +self+:
12155 *
12156 * s = "---abc+++"
12157 * s.strip("-+") # => "abc"
12158 * s.strip("+-") # => "abc"
12159 *
12160 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
12161 * and may use any of its valid forms, including negation, ranges, and escapes:
12162 *
12163 * "01234abc56789".strip("0-9") # "abc"
12164 * "01234abc56789".strip("0-9", "^4-6") # "4abc56"
12165 *
12166 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
12167 */
12168
12169static VALUE
12170rb_str_strip(int argc, VALUE *argv, VALUE str)
12171{
12172 const char *start;
12173 rb_len_t olen, loffset, roffset;
12174 rb_encoding *enc = STR_ENC_GET(str);
12175
12176 RSTRING_GETMEM(str, start, olen);
12177
12178 if (argc > 0) {
12179 char table[TR_TABLE_SIZE];
12180 VALUE del = 0, nodel = 0;
12181
12182 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12183
12184 /* the selector conversion may have modified str */
12185 enc = STR_ENC_GET(str);
12186 RSTRING_GETMEM(str, start, olen);
12187
12188 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12189 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12190 }
12191 else {
12192 loffset = lstrip_offset(str, start, start+olen, enc);
12193 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12194 }
12195
12196 if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
12197 return rb_str_subseq(str, loffset, olen-loffset-roffset);
12198}
12199
12200static VALUE
12201scan_once(VALUE str, VALUE pat, rb_len_t *start, int set_backref_str)
12202{
12203 VALUE result = Qnil;
12204 rb_len_t end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12205 if (pos >= 0) {
12206 VALUE match = Qnil;
12207 if (BUILTIN_TYPE(pat) == T_STRING) {
12208 end = pos + RSTRING_LEN(pat);
12209 }
12210 else {
12211 match = rb_backref_get();
12212 pos = RMATCH_BEG(match, 0);
12213 end = RMATCH_END(match, 0);
12214 }
12215
12216 if (pos == end) {
12217 rb_encoding *enc = STR_ENC_GET(str);
12218 /*
12219 * Always consume at least one character of the input string
12220 */
12221 if (RSTRING_LEN(str) > end)
12222 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12223 RSTRING_END(str), enc);
12224 else
12225 *start = end + 1;
12226 }
12227 else {
12228 *start = end;
12229 }
12230
12231 if (NIL_P(match) || RMATCH_NREGS(match) == 1) {
12232 result = rb_str_subseq(str, pos, end - pos);
12233 return result;
12234 }
12235 else {
12236 int num_regs = RMATCH_NREGS(match);
12237 result = rb_ary_new2(num_regs);
12238 for (int i = 1; i < num_regs; i++) {
12239 VALUE s = Qnil;
12240 if (RMATCH_BEG(match, i) >= 0) {
12241 s = rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12242 }
12243
12244 rb_ary_push(result, s);
12245 }
12246 }
12247
12248 RB_GC_GUARD(match);
12249 }
12250
12251 return result;
12252}
12253
12254
12255/*
12256 * call-seq:
12257 * scan(pattern) -> array_of_results
12258 * scan(pattern) {|result| ... } -> self
12259 *
12260 * :include: doc/string/scan.rdoc
12261 *
12262 */
12263
12264static VALUE
12265rb_str_scan(VALUE str, VALUE pat)
12266{
12267 VALUE result;
12268 rb_len_t start = 0;
12269 rb_len_t last = -1, prev = 0;
12270 const char *p = RSTRING_PTR(str);
12271 rb_len_t len = RSTRING_LEN(str);
12272
12273 pat = get_pat_quoted(pat, 1);
12274 mustnot_broken(str);
12275 if (!rb_block_given_p()) {
12276 VALUE ary = rb_ary_new();
12277
12278 while (!NIL_P(result = scan_once(str, pat, &start, 0))) {
12279 last = prev;
12280 prev = start;
12281 rb_ary_push(ary, result);
12282 }
12283 if (last >= 0) rb_pat_search(pat, str, last, 1);
12284 else rb_backref_set(Qnil);
12285 return ary;
12286 }
12287
12288 while (!NIL_P(result = scan_once(str, pat, &start, 1))) {
12289 last = prev;
12290 prev = start;
12291 rb_yield(result);
12292 str_mod_check(str, p, len);
12293 }
12294 if (last >= 0) rb_pat_search(pat, str, last, 1);
12295 return str;
12296}
12297
12298
12299/*
12300 * call-seq:
12301 * hex -> integer
12302 *
12303 * Interprets the leading substring of +self+ as hexadecimal, possibly signed;
12304 * returns its value as an integer.
12305 *
12306 * The leading substring is interpreted as hexadecimal when it begins with:
12307 *
12308 * - One or more character representing hexadecimal digits
12309 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
12310 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit:
12311 *
12312 * 'f'.hex # => 15
12313 * '11'.hex # => 17
12314 * 'FFF'.hex # => 4095
12315 * 'fffg'.hex # => 4095
12316 * 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not.
12317 * 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not.
12318 * 'deadbeef'.hex # => 3735928559
12319 *
12320 * - <tt>'0x'</tt> or <tt>'0X'</tt>, followed by one or more hexadecimal digits:
12321 *
12322 * '0xfff'.hex # => 4095
12323 * '0xfffg'.hex # => 4095
12324 *
12325 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
12326 *
12327 * '-fff'.hex # => -4095
12328 * '-0xFFF'.hex # => -4095
12329 *
12330 * For any substring not described above, returns zero:
12331 *
12332 * 'xxx'.hex # => 0
12333 * ''.hex # => 0
12334 *
12335 * Note that, unlike #oct, this method interprets only hexadecimal,
12336 * and not binary, octal, or decimal notations:
12337 *
12338 * '0b111'.hex # => 45329
12339 * '0o777'.hex # => 0
12340 * '0d999'.hex # => 55705
12341 *
12342 * Related: See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
12343 */
12344
12345static VALUE
12346rb_str_hex(VALUE str)
12347{
12348 return rb_str_to_inum(str, 16, FALSE);
12349}
12350
12351
12352/*
12353 * call-seq:
12354 * oct -> integer
12355 *
12356 * Interprets the leading substring of +self+ as octal, binary, decimal, or hexadecimal, possibly signed;
12357 * returns their value as an integer.
12358 *
12359 * In brief:
12360 *
12361 * # Interpreted as octal.
12362 * '777'.oct # => 511
12363 * '777x'.oct # => 511
12364 * '0777'.oct # => 511
12365 * '0o777'.oct # => 511
12366 * '-777'.oct # => -511
12367 * # Not interpreted as octal.
12368 * '0b111'.oct # => 7 # Interpreted as binary.
12369 * '0d999'.oct # => 999 # Interpreted as decimal.
12370 * '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
12371 *
12372 * The leading substring is interpreted as octal when it begins with:
12373 *
12374 * - One or more character representing octal digits
12375 * (each in the range <tt>'0'..'7'</tt>);
12376 * the string to be interpreted ends at the first character that does not represent an octal digit:
12377 *
12378 * '7'.oct @ => 7
12379 * '11'.oct # => 9
12380 * '777'.oct # => 511
12381 * '0777'.oct # => 511
12382 * '7778'.oct # => 511
12383 * '777x'.oct # => 511
12384 *
12385 * - <tt>'0o'</tt>, followed by one or more octal digits:
12386 *
12387 * '0o777'.oct # => 511
12388 * '0o7778'.oct # => 511
12389 *
12390 * The leading substring is _not_ interpreted as octal when it begins with:
12391 *
12392 * - <tt>'0b'</tt>, followed by one or more characters representing binary digits
12393 * (each in the range <tt>'0'..'1'</tt>);
12394 * the string to be interpreted ends at the first character that does not represent a binary digit.
12395 * the string is interpreted as binary digits (base 2):
12396 *
12397 * '0b111'.oct # => 7
12398 * '0b1112'.oct # => 7
12399 *
12400 * - <tt>'0d'</tt>, followed by one or more characters representing decimal digits
12401 * (each in the range <tt>'0'..'9'</tt>);
12402 * the string to be interpreted ends at the first character that does not represent a decimal digit.
12403 * the string is interpreted as decimal digits (base 10):
12404 *
12405 * '0d999'.oct # => 999
12406 * '0d999x'.oct # => 999
12407 *
12408 * - <tt>'0x'</tt>, followed by one or more characters representing hexadecimal digits
12409 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
12410 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit.
12411 * the string is interpreted as hexadecimal digits (base 16):
12412 *
12413 * '0xfff'.oct # => 4095
12414 * '0xfffg'.oct # => 4095
12415 *
12416 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
12417 *
12418 * '-777'.oct # => -511
12419 * '-0777'.oct # => -511
12420 * '-0b111'.oct # => -7
12421 * '-0xfff'.oct # => -4095
12422 *
12423 * For any substring not described above, returns zero:
12424 *
12425 * 'foo'.oct # => 0
12426 * ''.oct # => 0
12427 *
12428 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
12429 */
12430
12431static VALUE
12432rb_str_oct(VALUE str)
12433{
12434 return rb_str_to_inum(str, -8, FALSE);
12435}
12436
12437#ifndef HAVE_CRYPT_R
12438# include "ruby/thread_native.h"
12439# include "ruby/atomic.h"
12440
12441static struct {
12442 rb_nativethread_lock_t lock;
12443} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12444#endif
12445
12446/*
12447 * call-seq:
12448 * crypt(salt_str) -> new_string
12449 *
12450 * Returns the string generated by calling <code>crypt(3)</code>
12451 * standard library function with <code>str</code> and
12452 * <code>salt_str</code>, in this order, as its arguments. Please do
12453 * not use this method any longer. It is legacy; provided only for
12454 * backward compatibility with ruby scripts in earlier days. It is
12455 * bad to use in contemporary programs for several reasons:
12456 *
12457 * * Behaviour of C's <code>crypt(3)</code> depends on the OS it is
12458 * run. The generated string lacks data portability.
12459 *
12460 * * On some OSes such as Mac OS, <code>crypt(3)</code> never fails
12461 * (i.e. silently ends up in unexpected results).
12462 *
12463 * * On some OSes such as Mac OS, <code>crypt(3)</code> is not
12464 * thread safe.
12465 *
12466 * * So-called "traditional" usage of <code>crypt(3)</code> is very
12467 * very very weak. According to its manpage, Linux's traditional
12468 * <code>crypt(3)</code> output has only 2**56 variations; too
12469 * easy to brute force today. And this is the default behaviour.
12470 *
12471 * * In order to make things robust some OSes implement so-called
12472 * "modular" usage. To go through, you have to do a complex
12473 * build-up of the <code>salt_str</code> parameter, by hand.
12474 * Failure in generation of a proper salt string tends not to
12475 * yield any errors; typos in parameters are normally not
12476 * detectable.
12477 *
12478 * * For instance, in the following example, the second invocation
12479 * of String#crypt is wrong; it has a typo in "round=" (lacks
12480 * "s"). However the call does not fail and something unexpected
12481 * is generated.
12482 *
12483 * "foo".crypt("$5$rounds=1000$salt$") # OK, proper usage
12484 * "foo".crypt("$5$round=1000$salt$") # Typo not detected
12485 *
12486 * * Even in the "modular" mode, some hash functions are considered
12487 * archaic and no longer recommended at all; for instance module
12488 * <code>$1$</code> is officially abandoned by its author: see
12489 * http://phk.freebsd.dk/sagas/md5crypt_eol/ . For another
12490 * instance module <code>$3$</code> is considered completely
12491 * broken: see the manpage of FreeBSD.
12492 *
12493 * * On some OS such as Mac OS, there is no modular mode. Yet, as
12494 * written above, <code>crypt(3)</code> on Mac OS never fails.
12495 * This means even if you build up a proper salt string it
12496 * generates a traditional DES hash anyways, and there is no way
12497 * for you to be aware of.
12498 *
12499 * "foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
12500 *
12501 * If for some reason you cannot migrate to other secure contemporary
12502 * password hashing algorithms, install the string-crypt gem and
12503 * <code>require 'string/crypt'</code> to continue using it.
12504 */
12505
12506static VALUE
12507rb_str_crypt(VALUE str, VALUE salt)
12508{
12509#ifdef HAVE_CRYPT_R
12510 VALUE databuf;
12511 struct crypt_data *data;
12512# define CRYPT_END() ALLOCV_END(databuf)
12513#else
12514 char *tmp_buf;
12515 extern char *crypt(const char *, const char *);
12516# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12517#endif
12518 VALUE result;
12519 const char *s, *saltp, *res;
12520#ifdef BROKEN_CRYPT
12521 char salt_8bit_clean[3];
12522#endif
12523
12524 StringValue(salt);
12525 mustnot_wchar(str);
12526 mustnot_wchar(salt);
12527 s = StringValueCStr(str);
12528 saltp = RSTRING_PTR(salt);
12529 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12530 rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
12531 }
12532
12533#ifdef BROKEN_CRYPT
12534 if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) {
12535 salt_8bit_clean[0] = saltp[0] & 0x7f;
12536 salt_8bit_clean[1] = saltp[1] & 0x7f;
12537 salt_8bit_clean[2] = '\0';
12538 saltp = salt_8bit_clean;
12539 }
12540#endif
12541#ifdef HAVE_CRYPT_R
12542 data = ALLOCV(databuf, sizeof(struct crypt_data));
12543# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12544 data->initialized = 0;
12545# endif
12546 res = crypt_r(s, saltp, data);
12547#else
12548 rb_nativethread_lock_lock(&crypt_mutex.lock);
12549 res = crypt(s, saltp);
12550#endif
12551 if (!res) {
12552 int err = errno;
12553 CRYPT_END();
12554 rb_syserr_fail(err, "crypt");
12555 }
12556#ifdef HAVE_CRYPT_R
12557 result = rb_str_new_cstr(res);
12558 CRYPT_END();
12559#else
12560 // We need to copy this buffer because it's static and we need to unlock the mutex
12561 // before allocating a new object (the string to be returned). If we allocate while
12562 // holding the lock, we could run GC which fires the VM barrier and causes a deadlock
12563 // if other ractors are waiting on this lock.
12564 size_t res_size = strlen(res);
12565 tmp_buf = ALLOCA_N(char, res_size); // should be small enough to alloca
12566 memcpy(tmp_buf, res, res_size);
12567 CRYPT_END();
12568 result = rb_str_new(tmp_buf, res_size);
12569#endif
12570 return result;
12571}
12572
12573
12574/*
12575 * call-seq:
12576 * ord -> integer
12577 *
12578 * :include: doc/string/ord.rdoc
12579 *
12580 */
12581
12582static VALUE
12583rb_str_ord(VALUE s)
12584{
12585 unsigned int c;
12586
12587 c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
12588 return UINT2NUM(c);
12589}
12590/*
12591 * call-seq:
12592 * sum(n = 16) -> integer
12593 *
12594 * :include: doc/string/sum.rdoc
12595 *
12596 */
12597
12598static VALUE
12599rb_str_sum(int argc, VALUE *argv, VALUE str)
12600{
12601 int bits = 16;
12602 char *ptr, *p, *pend;
12603 rb_len_t len;
12604 VALUE sum = INT2FIX(0);
12605 unsigned long sum0 = 0;
12606
12607 if (rb_check_arity(argc, 0, 1) && (bits = NUM2INT(argv[0])) < 0) {
12608 bits = 0;
12609 }
12610 ptr = p = RSTRING_PTR(str);
12611 len = RSTRING_LEN(str);
12612 pend = p + len;
12613
12614 while (p < pend) {
12615 if (FIXNUM_MAX - UCHAR_MAX < sum0) {
12616 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12617 str_mod_check(str, ptr, len);
12618 sum0 = 0;
12619 }
12620 sum0 += (unsigned char)*p;
12621 p++;
12622 }
12623
12624 if (bits == 0) {
12625 if (sum0) {
12626 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12627 }
12628 }
12629 else {
12630 if (sum == INT2FIX(0)) {
12631 if (bits < (int)sizeof(long)*CHAR_BIT) {
12632 sum0 &= (((unsigned long)1)<<bits)-1;
12633 }
12634 sum = LONG2FIX(sum0);
12635 }
12636 else {
12637 VALUE mod;
12638
12639 if (sum0) {
12640 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
12641 }
12642
12643 mod = rb_funcall(INT2FIX(1), idLTLT, 1, INT2FIX(bits));
12644 mod = rb_funcall(mod, '-', 1, INT2FIX(1));
12645 sum = rb_funcall(sum, '&', 1, mod);
12646 }
12647 }
12648 return sum;
12649}
12650
12651static VALUE
12652rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
12653{
12654 rb_encoding *enc;
12655 VALUE w;
12656 rb_len_t width, len, flen = 1, fclen = 1;
12657 VALUE res;
12658 char *p;
12659 const char *f = " ";
12660 rb_len_t n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12661 VALUE pad;
12662 int singlebyte = 1, cr;
12663 int termlen;
12664
12665 rb_scan_args(argc, argv, "11", &w, &pad);
12666 enc = STR_ENC_GET(str);
12667 width = NUM2LEN(w);
12668 if (argc == 2) {
12669 StringValue(pad);
12670 enc = rb_enc_check(str, pad);
12671 f = RSTRING_PTR(pad);
12672 flen = RSTRING_LEN(pad);
12673 fclen = str_strlen(pad, enc); /* rb_enc_check */
12674 singlebyte = single_byte_optimizable(pad);
12675 if (flen == 0 || fclen == 0) {
12676 rb_raise(rb_eArgError, "zero width padding");
12677 }
12678 }
12679 termlen = rb_enc_mbminlen(enc);
12680 len = str_strlen(str, enc); /* rb_enc_check */
12681 if (width < 0 || len >= width) return str_duplicate(rb_cString, str);
12682 n = width - len;
12683 llen = (jflag == 'l') ? 0 : ((jflag == 'r') ? n : n/2);
12684 rlen = n - llen;
12685 cr = ENC_CODERANGE(str);
12686 if (flen > 1) {
12687 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12688 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12689 }
12690 size = RSTRING_LEN(str);
12691 if ((len = llen / fclen + rlen / fclen) >= RB_LEN_MAX / flen ||
12692 (len *= flen) >= RB_LEN_MAX - llen2 - rlen2 ||
12693 (len += llen2 + rlen2) >= RB_LEN_MAX - size) {
12694 rb_raise(rb_eArgError, "argument too big");
12695 }
12696 len += size;
12697 res = str_enc_new(rb_cString, 0, len, enc);
12698 p = RSTRING_PTR(res);
12699 if (flen <= 1) {
12700 memset(p, *f, llen);
12701 p += llen;
12702 }
12703 else {
12704 while (llen >= fclen) {
12705 memcpy(p,f,flen);
12706 p += flen;
12707 llen -= fclen;
12708 }
12709 if (llen > 0) {
12710 memcpy(p, f, llen2);
12711 p += llen2;
12712 }
12713 }
12714 memcpy(p, RSTRING_PTR(str), size);
12715 p += size;
12716 if (flen <= 1) {
12717 memset(p, *f, rlen);
12718 p += rlen;
12719 }
12720 else {
12721 while (rlen >= fclen) {
12722 memcpy(p,f,flen);
12723 p += flen;
12724 rlen -= fclen;
12725 }
12726 if (rlen > 0) {
12727 memcpy(p, f, rlen2);
12728 p += rlen2;
12729 }
12730 }
12731 TERM_FILL(p, termlen);
12732 STR_SET_LEN(res, p-RSTRING_PTR(res));
12733
12734 if (argc == 2)
12735 cr = ENC_CODERANGE_AND(cr, ENC_CODERANGE(pad));
12736 if (cr != ENC_CODERANGE_BROKEN)
12737 ENC_CODERANGE_SET(res, cr);
12738
12739 RB_GC_GUARD(pad);
12740 return res;
12741}
12742
12743
12744/*
12745 * call-seq:
12746 * ljust(width, pad_string = ' ') -> new_string
12747 *
12748 * :include: doc/string/ljust.rdoc
12749 *
12750 */
12751
12752static VALUE
12753rb_str_ljust(int argc, VALUE *argv, VALUE str)
12754{
12755 return rb_str_justify(argc, argv, str, 'l');
12756}
12757
12758/*
12759 * call-seq:
12760 * rjust(width, pad_string = ' ') -> new_string
12761 *
12762 * :include: doc/string/rjust.rdoc
12763 *
12764 */
12765
12766static VALUE
12767rb_str_rjust(int argc, VALUE *argv, VALUE str)
12768{
12769 return rb_str_justify(argc, argv, str, 'r');
12770}
12771
12772
12773/*
12774 * call-seq:
12775 * center(size, pad_string = ' ') -> new_string
12776 *
12777 * :include: doc/string/center.rdoc
12778 *
12779 */
12780
12781static VALUE
12782rb_str_center(int argc, VALUE *argv, VALUE str)
12783{
12784 return rb_str_justify(argc, argv, str, 'c');
12785}
12786
12787/*
12788 * call-seq:
12789 * partition(pattern) -> [pre_match, first_match, post_match]
12790 *
12791 * :include: doc/string/partition.rdoc
12792 *
12793 */
12794
12795static VALUE
12796rb_str_partition(VALUE str, VALUE sep)
12797{
12798 rb_len_t pos;
12799
12800 sep = get_pat_quoted(sep, 0);
12801 if (RB_TYPE_P(sep, T_REGEXP)) {
12802 if (rb_reg_search(sep, str, 0, 0) < 0) {
12803 goto failed;
12804 }
12805 VALUE match = rb_backref_get();
12806
12807 pos = RMATCH_BEG(match, 0);
12808 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12809 }
12810 else {
12811 pos = rb_str_index(str, sep, 0);
12812 if (pos < 0) goto failed;
12813 }
12814
12815 rb_len_t rpos = pos + RSTRING_LEN(sep);
12816 if (rpos > RSTRING_LEN(str)) goto failed;
12817 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12818 sep,
12819 rb_str_subseq(str, rpos, RSTRING_LEN(str)-rpos));
12820
12821 failed:
12822 return rb_ary_new3(3, str_duplicate(rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12823}
12824
12825/*
12826 * call-seq:
12827 * rpartition(pattern) -> [pre_match, last_match, post_match]
12828 *
12829 * :include: doc/string/rpartition.rdoc
12830 *
12831 */
12832
12833static VALUE
12834rb_str_rpartition(VALUE str, VALUE sep)
12835{
12836 rb_len_t pos;
12837
12838 sep = get_pat_quoted(sep, 0);
12839 if (RB_TYPE_P(sep, T_REGEXP)) {
12840 pos = RSTRING_LEN(str);
12841 if (rb_reg_search(sep, str, pos, 1) < 0) {
12842 goto failed;
12843 }
12844 VALUE match = rb_backref_get();
12845
12846 pos = RMATCH_BEG(match, 0);
12847 sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
12848 }
12849 else {
12850 /* str may have been modified by #to_str above */
12851 pos = rb_str_sublen(str, RSTRING_LEN(str));
12852 pos = rb_str_rindex(str, sep, pos);
12853 if (pos < 0) {
12854 goto failed;
12855 }
12856 }
12857
12858 rb_len_t rpos = pos + RSTRING_LEN(sep);
12859 if (rpos > RSTRING_LEN(str)) goto failed;
12860 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
12861 sep,
12862 rb_str_subseq(str, rpos, RSTRING_LEN(str)-rpos));
12863 failed:
12864 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(rb_cString, str));
12865}
12866
12867/*
12868 * call-seq:
12869 * start_with?(*patterns) -> true or false
12870 *
12871 * :include: doc/string/start_with_p.rdoc
12872 *
12873 */
12874
12875static VALUE
12876rb_str_start_with(int argc, VALUE *argv, VALUE str)
12877{
12878 int i;
12879
12880 for (i=0; i<argc; i++) {
12881 VALUE tmp = argv[i];
12882 if (RB_TYPE_P(tmp, T_REGEXP)) {
12883 if (rb_reg_start_with_p(tmp, str))
12884 return Qtrue;
12885 }
12886 else {
12887 const char *p, *s, *e;
12888 rb_len_t slen, tlen;
12889 rb_encoding *enc;
12890
12891 StringValue(tmp);
12892 enc = rb_enc_check(str, tmp);
12893 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12894 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12895 p = RSTRING_PTR(str);
12896 e = p + slen;
12897 s = p + tlen;
12898 if (!at_char_right_boundary(p, s, e, enc))
12899 continue;
12900 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12901 return Qtrue;
12902 }
12903 }
12904 return Qfalse;
12905}
12906
12907/*
12908 * call-seq:
12909 * end_with?(*strings) -> true or false
12910 *
12911 * :include: doc/string/end_with_p.rdoc
12912 *
12913 */
12914
12915static VALUE
12916rb_str_end_with(int argc, VALUE *argv, VALUE str)
12917{
12918 int i;
12919
12920 for (i=0; i<argc; i++) {
12921 VALUE tmp = argv[i];
12922 const char *p, *s, *e;
12923 rb_len_t slen, tlen;
12924 rb_encoding *enc;
12925
12926 StringValue(tmp);
12927 enc = rb_enc_check(str, tmp);
12928 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
12929 if ((slen = RSTRING_LEN(str)) < tlen) continue;
12930 p = RSTRING_PTR(str);
12931 e = p + slen;
12932 s = e - tlen;
12933 if (!at_char_boundary(p, s, e, enc))
12934 continue;
12935 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12936 return Qtrue;
12937 }
12938 return Qfalse;
12939}
12940
12950static rb_len_t
12951deleted_prefix_length(VALUE str, VALUE prefix)
12952{
12953 const char *strptr, *prefixptr;
12954 rb_len_t olen, prefixlen;
12955 rb_encoding *enc = rb_enc_get(str);
12956
12957 StringValue(prefix);
12958
12959 if (!is_broken_string(prefix) ||
12960 !rb_enc_asciicompat(enc) ||
12961 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12962 enc = rb_enc_check(str, prefix);
12963 }
12964
12965 /* return 0 if not start with prefix */
12966 prefixlen = RSTRING_LEN(prefix);
12967 if (prefixlen <= 0) return 0;
12968 olen = RSTRING_LEN(str);
12969 if (olen < prefixlen) return 0;
12970 strptr = RSTRING_PTR(str);
12971 prefixptr = RSTRING_PTR(prefix);
12972 if (memcmp(strptr, prefixptr, prefixlen) != 0) return 0;
12973 if (is_broken_string(prefix)) {
12974 if (!is_broken_string(str)) {
12975 /* prefix in a valid string cannot be broken */
12976 return 0;
12977 }
12978 const char *strend = strptr + olen;
12979 const char *after_prefix = strptr + prefixlen;
12980 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12981 /* prefix does not end at char-boundary */
12982 return 0;
12983 }
12984 }
12985 /* prefix part in `str` also should be valid. */
12986
12987 return prefixlen;
12988}
12989
12990/*
12991 * call-seq:
12992 * delete_prefix!(prefix) -> self or nil
12993 *
12994 * Like String#delete_prefix, except that +self+ is modified in place;
12995 * returns +self+ if the prefix is removed, +nil+ otherwise.
12996 *
12997 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12998 */
12999
13000static VALUE
13001rb_str_delete_prefix_bang(VALUE str, VALUE prefix)
13002{
13003 rb_len_t prefixlen;
13004 str_modify_keep_cr(str);
13005
13006 prefixlen = deleted_prefix_length(str, prefix);
13007 if (prefixlen <= 0) return Qnil;
13008
13009 return rb_str_drop_bytes(str, prefixlen);
13010}
13011
13012/*
13013 * call-seq:
13014 * delete_prefix(prefix) -> new_string
13015 *
13016 * :include: doc/string/delete_prefix.rdoc
13017 *
13018 */
13019
13020static VALUE
13021rb_str_delete_prefix(VALUE str, VALUE prefix)
13022{
13023 rb_len_t prefixlen;
13024
13025 prefixlen = deleted_prefix_length(str, prefix);
13026 if (prefixlen <= 0) return str_duplicate(rb_cString, str);
13027
13028 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
13029}
13030
13040static rb_len_t
13041deleted_suffix_length(VALUE str, VALUE suffix)
13042{
13043 const char *strptr, *suffixptr;
13044 rb_len_t olen, suffixlen;
13045 rb_encoding *enc;
13046
13047 StringValue(suffix);
13048 if (is_broken_string(suffix)) return 0;
13049 enc = rb_enc_check(str, suffix);
13050
13051 /* return 0 if not start with suffix */
13052 suffixlen = RSTRING_LEN(suffix);
13053 if (suffixlen <= 0) return 0;
13054 olen = RSTRING_LEN(str);
13055 if (olen < suffixlen) return 0;
13056 strptr = RSTRING_PTR(str);
13057 suffixptr = RSTRING_PTR(suffix);
13058 const char *strend = strptr + olen;
13059 const char *before_suffix = strend - suffixlen;
13060 if (memcmp(before_suffix, suffixptr, suffixlen) != 0) return 0;
13061 if (!at_char_boundary(strptr, before_suffix, strend, enc)) return 0;
13062
13063 return suffixlen;
13064}
13065
13066/*
13067 * call-seq:
13068 * delete_suffix!(suffix) -> self or nil
13069 *
13070 * Like String#delete_suffix, except that +self+ is modified in place;
13071 * returns +self+ if the suffix is removed, +nil+ otherwise.
13072 *
13073 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13074 */
13075
13076static VALUE
13077rb_str_delete_suffix_bang(VALUE str, VALUE suffix)
13078{
13079 rb_len_t suffixlen;
13080 str_modifiable(str);
13081
13082 suffixlen = deleted_suffix_length(str, suffix);
13083 if (suffixlen <= 0) return Qnil;
13084
13085 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
13086}
13087
13088/*
13089 * call-seq:
13090 * delete_suffix(suffix) -> new_string
13091 *
13092 * :include: doc/string/delete_suffix.rdoc
13093 *
13094 */
13095
13096static VALUE
13097rb_str_delete_suffix(VALUE str, VALUE suffix)
13098{
13099 rb_len_t suffixlen;
13100
13101 suffixlen = deleted_suffix_length(str, suffix);
13102 if (suffixlen <= 0) return str_duplicate(rb_cString, str);
13103
13104 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
13105}
13106
13107void
13108rb_str_setter(VALUE val, ID id, VALUE *var)
13109{
13110 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING)) {
13111 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
13112 }
13113 *var = val;
13114}
13115
13116static void
13117nil_setter_warning(ID id)
13118{
13119 rb_warn_deprecated("non-nil '%"PRIsVALUE"'", NULL, rb_id2str(id));
13120}
13121
13122void
13123rb_deprecated_str_setter(VALUE val, ID id, VALUE *var)
13124{
13125 rb_str_setter(val, id, var);
13126 if (!NIL_P(*var)) {
13127 nil_setter_warning(id);
13128 }
13129}
13130
13131static void
13132rb_fs_setter(VALUE val, ID id, VALUE *var)
13133{
13134 val = rb_fs_check(val);
13135 if (!val) {
13136 rb_raise(rb_eTypeError,
13137 "value of %"PRIsVALUE" must be String or Regexp",
13138 rb_id2str(id));
13139 }
13140 if (!NIL_P(val)) {
13141 nil_setter_warning(id);
13142 }
13143 *var = val;
13144}
13145
13146
13147/*
13148 * call-seq:
13149 * force_encoding(encoding) -> self
13150 *
13151 * :include: doc/string/force_encoding.rdoc
13152 *
13153 */
13154
13155static VALUE
13156rb_str_force_encoding(VALUE str, VALUE enc)
13157{
13158 str_modifiable(str);
13159
13160 rb_encoding *encoding = rb_to_encoding(enc);
13161 int idx = rb_enc_to_index(encoding);
13162
13163 // If the encoding is unchanged, we do nothing.
13164 if (ENCODING_GET(str) == idx) {
13165 return str;
13166 }
13167
13168 rb_enc_associate_index(str, idx);
13169
13170 // If the coderange was 7bit and the new encoding is ASCII-compatible
13171 // we can keep the coderange.
13172 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT && encoding && rb_enc_asciicompat(encoding)) {
13173 return str;
13174 }
13175
13177 return str;
13178}
13179
13180/*
13181 * call-seq:
13182 * b -> new_string
13183 *
13184 * :include: doc/string/b.rdoc
13185 *
13186 */
13187
13188static VALUE
13189rb_str_b(VALUE str)
13190{
13191 VALUE str2;
13192 if (STR_EMBED_P(str)) {
13193 str2 = str_alloc_embed(rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13194 }
13195 else {
13196 str2 = str_alloc_heap(rb_cString);
13197 }
13198 str_replace_shared_without_enc(str2, str);
13199
13200 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13201 // BINARY strings can never be broken; they're either 7-bit ASCII or VALID.
13202 // If we know the receiver's code range then we know the result's code range.
13203 int cr = ENC_CODERANGE(str);
13204 switch (cr) {
13205 case ENC_CODERANGE_7BIT:
13207 break;
13211 break;
13212 default:
13213 ENC_CODERANGE_CLEAR(str2);
13214 break;
13215 }
13216 }
13217
13218 return str2;
13219}
13220
13221/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
13222static VALUE
13223rb_str_valid_encoding_p(VALUE str)
13224{
13225 int cr = rb_enc_str_coderange(str);
13226
13227 return RBOOL(cr != ENC_CODERANGE_BROKEN);
13228}
13229
13230/* Defined as a leaf builtin in string.rb, so this must never raise or call into Ruby. */
13231static VALUE
13232rb_str_is_ascii_only_p(VALUE str)
13233{
13234 int cr = rb_enc_str_coderange(str);
13235
13236 return RBOOL(cr == ENC_CODERANGE_7BIT);
13237}
13238
13239VALUE
13241{
13242 static const char ellipsis[] = "...";
13243 const rb_len_t ellipsislen = sizeof(ellipsis) - 1;
13244 rb_encoding *const enc = rb_enc_get(str);
13245 const rb_len_t blen = RSTRING_LEN(str);
13246 const char *const p = RSTRING_PTR(str), *e = p + blen;
13247 VALUE estr, ret = 0;
13248
13249 if (len < 0) rb_raise(rb_eIndexError, "negative length %"PRIdLEN, len);
13250 if (len * rb_enc_mbminlen(enc) >= blen ||
13251 (e = rb_enc_nth(p, e, len, enc)) - p == blen) {
13252 ret = str;
13253 }
13254 else if (len <= ellipsislen ||
13255 !(e = rb_enc_step_back(p, e, e, len = ellipsislen, enc))) {
13256 if (rb_enc_asciicompat(enc)) {
13257 ret = rb_str_new(ellipsis, len);
13258 rb_enc_associate(ret, enc);
13259 }
13260 else {
13261 estr = rb_usascii_str_new(ellipsis, len);
13262 ret = rb_str_encode(estr, rb_enc_from_encoding(enc), 0, Qnil);
13263 }
13264 }
13265 else if (ret = rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13266 rb_str_cat(ret, ellipsis, ellipsislen);
13267 }
13268 else {
13269 estr = rb_str_encode(rb_usascii_str_new(ellipsis, ellipsislen),
13270 rb_enc_from_encoding(enc), 0, Qnil);
13271 rb_str_append(ret, estr);
13272 }
13273 return ret;
13274}
13275
13276static VALUE
13277str_compat_and_valid(VALUE str, rb_encoding *enc)
13278{
13279 int cr;
13280 str = StringValue(str);
13281 cr = rb_enc_str_coderange(str);
13282 if (cr == ENC_CODERANGE_BROKEN) {
13283 rb_raise(rb_eArgError, "replacement must be valid byte sequence '%+"PRIsVALUE"'", str);
13284 }
13285 else {
13286 rb_encoding *e = STR_ENC_GET(str);
13287 if (cr == ENC_CODERANGE_7BIT ? rb_enc_mbminlen(enc) != 1 : enc != e) {
13288 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
13289 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13290 }
13291 }
13292 return str;
13293}
13294
13295static VALUE enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr);
13296
13297VALUE
13299{
13300 rb_encoding *enc = STR_ENC_GET(str);
13301 return enc_str_scrub(enc, str, repl, ENC_CODERANGE(str));
13302}
13303
13304VALUE
13305rb_enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl)
13306{
13307 int cr = ENC_CODERANGE_UNKNOWN;
13308 if (enc == STR_ENC_GET(str)) {
13309 /* cached coderange makes sense only when enc equals the
13310 * actual encoding of str */
13311 cr = ENC_CODERANGE(str);
13312 }
13313 return enc_str_scrub(enc, str, repl, cr);
13314}
13315
13316static VALUE
13317enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
13318{
13319 int encidx;
13320 VALUE buf = Qnil;
13321 const char *rep, *p, *e, *p1, *sp;
13322 rb_len_t replen = -1;
13323 rb_len_t slen;
13324
13325 if (rb_block_given_p()) {
13326 if (!NIL_P(repl))
13327 rb_raise(rb_eArgError, "both of block and replacement given");
13328 replen = 0;
13329 }
13330
13331 if (ENC_CODERANGE_CLEAN_P(cr))
13332 return Qnil;
13333
13334 if (!NIL_P(repl)) {
13335 repl = str_compat_and_valid(repl, enc);
13336 }
13337
13338 if (rb_enc_dummy_p(enc)) {
13339 return Qnil;
13340 }
13341 encidx = rb_enc_to_index(enc);
13342
13343#define DEFAULT_REPLACE_CHAR(str) do { \
13344 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13345 rep = replace; replen = (int)sizeof(replace); \
13346 } while (0)
13347
13348 slen = RSTRING_LEN(str);
13349 p = RSTRING_PTR(str);
13350 e = RSTRING_END(str);
13351 p1 = p;
13352 sp = p;
13353
13354 if (rb_enc_asciicompat(enc)) {
13355 int rep7bit_p;
13356 if (!replen) {
13357 rep = NULL;
13358 rep7bit_p = FALSE;
13359 }
13360 else if (!NIL_P(repl)) {
13361 rep = RSTRING_PTR(repl);
13362 replen = RSTRING_LEN(repl);
13363 rep7bit_p = (ENC_CODERANGE(repl) == ENC_CODERANGE_7BIT);
13364 }
13365 else if (encidx == rb_utf8_encindex()) {
13366 DEFAULT_REPLACE_CHAR("\xEF\xBF\xBD");
13367 rep7bit_p = FALSE;
13368 }
13369 else {
13370 DEFAULT_REPLACE_CHAR("?");
13371 rep7bit_p = TRUE;
13372 }
13373 cr = ENC_CODERANGE_7BIT;
13374
13375 p = search_nonascii(p, e);
13376 if (!p) {
13377 p = e;
13378 }
13379 while (p < e) {
13380 int ret = rb_enc_precise_mbclen(p, e, enc);
13381 if (MBCLEN_NEEDMORE_P(ret)) {
13382 break;
13383 }
13384 else if (MBCLEN_CHARFOUND_P(ret)) {
13386 p += MBCLEN_CHARFOUND_LEN(ret);
13387 /* After a multibyte character, fast-skip the following ASCII run. */
13388 p = search_nonascii(p, e);
13389 if (!p) {
13390 p = e;
13391 break;
13392 }
13393 }
13394 else if (MBCLEN_INVALID_P(ret)) {
13395 /*
13396 * p1~p: valid ascii/multibyte chars
13397 * p ~e: invalid bytes + unknown bytes
13398 */
13399 rb_len_t clen = rb_enc_mbmaxlen(enc);
13400 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
13401 if (p > p1) {
13402 rb_str_buf_cat(buf, p1, p - p1);
13403 }
13404
13405 if (e - p < clen) clen = e - p;
13406 if (clen <= 2) {
13407 clen = 1;
13408 }
13409 else {
13410 const char *q = p;
13411 clen--;
13412 for (; clen > 1; clen--) {
13413 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13414 if (MBCLEN_NEEDMORE_P(ret)) break;
13415 if (MBCLEN_INVALID_P(ret)) continue;
13417 }
13418 }
13419 if (rep) {
13420 rb_str_buf_cat(buf, rep, replen);
13421 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
13422 }
13423 else {
13424 repl = rb_yield(rb_enc_str_new(p, clen, enc));
13425 str_mod_check(str, sp, slen);
13426 repl = str_compat_and_valid(repl, enc);
13427 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13430 }
13431 p += clen;
13432 p1 = p;
13433 p = search_nonascii(p, e);
13434 if (!p) {
13435 p = e;
13436 break;
13437 }
13438 }
13439 else {
13441 }
13442 }
13443 if (NIL_P(buf)) {
13444 if (p == e) {
13445 ENC_CODERANGE_SET(str, cr);
13446 return Qnil;
13447 }
13448 buf = rb_str_buf_new(RSTRING_LEN(str));
13449 }
13450 if (p1 < p) {
13451 rb_str_buf_cat(buf, p1, p - p1);
13452 }
13453 if (p < e) {
13454 if (rep) {
13455 rb_str_buf_cat(buf, rep, replen);
13456 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
13457 }
13458 else {
13459 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
13460 str_mod_check(str, sp, slen);
13461 repl = str_compat_and_valid(repl, enc);
13462 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13465 }
13466 }
13467 }
13468 else {
13469 /* ASCII incompatible */
13470 rb_len_t mbminlen = rb_enc_mbminlen(enc);
13471 if (!replen) {
13472 rep = NULL;
13473 }
13474 else if (!NIL_P(repl)) {
13475 rep = RSTRING_PTR(repl);
13476 replen = RSTRING_LEN(repl);
13477 }
13478 else if (encidx == ENCINDEX_UTF_16BE) {
13479 DEFAULT_REPLACE_CHAR("\xFF\xFD");
13480 }
13481 else if (encidx == ENCINDEX_UTF_16LE) {
13482 DEFAULT_REPLACE_CHAR("\xFD\xFF");
13483 }
13484 else if (encidx == ENCINDEX_UTF_32BE) {
13485 DEFAULT_REPLACE_CHAR("\x00\x00\xFF\xFD");
13486 }
13487 else if (encidx == ENCINDEX_UTF_32LE) {
13488 DEFAULT_REPLACE_CHAR("\xFD\xFF\x00\x00");
13489 }
13490 else {
13491 DEFAULT_REPLACE_CHAR("?");
13492 }
13493
13494 while (p < e) {
13495 int ret = rb_enc_precise_mbclen(p, e, enc);
13496 if (MBCLEN_NEEDMORE_P(ret)) {
13497 break;
13498 }
13499 else if (MBCLEN_CHARFOUND_P(ret)) {
13500 p += MBCLEN_CHARFOUND_LEN(ret);
13501 }
13502 else if (MBCLEN_INVALID_P(ret)) {
13503 const char *q = p;
13504 rb_len_t clen = rb_enc_mbmaxlen(enc);
13505 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
13506 if (p > p1) rb_str_buf_cat(buf, p1, p - p1);
13507
13508 if (e - p < clen) clen = e - p;
13509 if (clen <= mbminlen * 2) {
13510 clen = mbminlen;
13511 }
13512 else {
13513 clen -= mbminlen;
13514 for (; clen > mbminlen; clen-=mbminlen) {
13515 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13516 if (MBCLEN_NEEDMORE_P(ret)) break;
13517 if (MBCLEN_INVALID_P(ret)) continue;
13519 }
13520 }
13521 if (rep) {
13522 rb_str_buf_cat(buf, rep, replen);
13523 }
13524 else {
13525 repl = rb_yield(rb_enc_str_new(p, clen, enc));
13526 str_mod_check(str, sp, slen);
13527 repl = str_compat_and_valid(repl, enc);
13528 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13529 }
13530 p += clen;
13531 p1 = p;
13532 }
13533 else {
13535 }
13536 }
13537 if (NIL_P(buf)) {
13538 if (p == e) {
13540 return Qnil;
13541 }
13542 buf = rb_str_buf_new(RSTRING_LEN(str));
13543 }
13544 if (p1 < p) {
13545 rb_str_buf_cat(buf, p1, p - p1);
13546 }
13547 if (p < e) {
13548 if (rep) {
13549 rb_str_buf_cat(buf, rep, replen);
13550 }
13551 else {
13552 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
13553 str_mod_check(str, sp, slen);
13554 repl = str_compat_and_valid(repl, enc);
13555 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
13556 }
13557 }
13559 }
13560 ENCODING_CODERANGE_SET(buf, rb_enc_to_index(enc), cr);
13561 return buf;
13562}
13563
13564/*
13565 * call-seq:
13566 * scrub(replacement_string = default_replacement_string) -> new_string
13567 * scrub{|sequence| ... } -> new_string
13568 *
13569 * :include: doc/string/scrub.rdoc
13570 *
13571 */
13572static VALUE
13573str_scrub(int argc, VALUE *argv, VALUE str)
13574{
13575 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13576 VALUE new = rb_str_scrub(str, repl);
13577 return NIL_P(new) ? str_duplicate(rb_cString, str): new;
13578}
13579
13580/*
13581 * call-seq:
13582 * scrub!(replacement_string = default_replacement_string) -> self
13583 * scrub!{|sequence| ... } -> self
13584 *
13585 * Like String#scrub, except that:
13586 *
13587 * - Any replacements are made in +self+.
13588 * - Returns +self+.
13589 *
13590 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13591 *
13592 */
13593static VALUE
13594str_scrub_bang(int argc, VALUE *argv, VALUE str)
13595{
13596 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
13597 VALUE new = rb_str_scrub(str, repl);
13598 if (!NIL_P(new)) rb_str_replace(str, new);
13599 return str;
13600}
13601
13602static ID id_normalize;
13603static ID id_normalized_p;
13604static VALUE mUnicodeNormalize;
13605
13606static VALUE
13607unicode_normalize_common(int argc, VALUE *argv, VALUE str, ID id)
13608{
13609 static int UnicodeNormalizeRequired = 0;
13610 VALUE argv2[2];
13611
13612 if (!UnicodeNormalizeRequired) {
13613 rb_require("unicode_normalize/normalize.rb");
13614 UnicodeNormalizeRequired = 1;
13615 }
13616 argv2[0] = str;
13617 if (rb_check_arity(argc, 0, 1)) argv2[1] = argv[0];
13618 return rb_funcallv(mUnicodeNormalize, id, argc+1, argv2);
13619}
13620
13621/*
13622 * call-seq:
13623 * unicode_normalize(form = :nfc) -> string
13624 *
13625 * :include: doc/string/unicode_normalize.rdoc
13626 *
13627 */
13628static VALUE
13629rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
13630{
13631 return unicode_normalize_common(argc, argv, str, id_normalize);
13632}
13633
13634/*
13635 * call-seq:
13636 * unicode_normalize!(form = :nfc) -> self
13637 *
13638 * Like String#unicode_normalize, except that the normalization
13639 * is performed on +self+ (not on a copy of +self+).
13640 *
13641 * Related: see {Modifying}[rdoc-ref:String@Modifying].
13642 *
13643 */
13644static VALUE
13645rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
13646{
13647 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13648}
13649
13650/* call-seq:
13651 * unicode_normalized?(form = :nfc) -> true or false
13652 *
13653 * Returns whether +self+ is in the given +form+ of Unicode normalization;
13654 * see String#unicode_normalize.
13655 *
13656 * The +form+ must be one of +:nfc+, +:nfd+, +:nfkc+, or +:nfkd+.
13657 *
13658 * Examples:
13659 *
13660 * "a\u0300".unicode_normalized? # => false
13661 * "a\u0300".unicode_normalized?(:nfd) # => true
13662 * "\u00E0".unicode_normalized? # => true
13663 * "\u00E0".unicode_normalized?(:nfd) # => false
13664 *
13665 *
13666 * Raises an exception if +self+ is not in a Unicode encoding:
13667 *
13668 * s = "\xE0".force_encoding(Encoding::ISO_8859_1)
13669 * s.unicode_normalized? # Raises Encoding::CompatibilityError
13670 *
13671 * Related: see {Querying}[rdoc-ref:String@Querying].
13672 */
13673static VALUE
13674rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
13675{
13676 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13677}
13678
13679/**********************************************************************
13680 * Document-class: Symbol
13681 *
13682 * A +Symbol+ object represents a named identifier inside the Ruby interpreter.
13683 *
13684 * You can create a +Symbol+ object explicitly with:
13685 *
13686 * - A {symbol literal}[rdoc-ref:syntax/literals.rdoc@Symbol+Literals].
13687 *
13688 * The same +Symbol+ object will be
13689 * created for a given name or string for the duration of a program's
13690 * execution, regardless of the context or meaning of that name. Thus
13691 * if <code>Fred</code> is a constant in one context, a method in
13692 * another, and a class in a third, the +Symbol+ <code>:Fred</code>
13693 * will be the same object in all three contexts.
13694 *
13695 * module One
13696 * class Fred
13697 * end
13698 * $f1 = :Fred
13699 * end
13700 * module Two
13701 * Fred = 1
13702 * $f2 = :Fred
13703 * end
13704 * def Fred()
13705 * end
13706 * $f3 = :Fred
13707 * $f1.object_id #=> 2514190
13708 * $f2.object_id #=> 2514190
13709 * $f3.object_id #=> 2514190
13710 *
13711 * Constant, method, and variable names are returned as symbols:
13712 *
13713 * module One
13714 * Two = 2
13715 * def three; 3 end
13716 * @four = 4
13717 * @@five = 5
13718 * $six = 6
13719 * end
13720 * seven = 7
13721 *
13722 * One.constants
13723 * # => [:Two]
13724 * One.instance_methods(true)
13725 * # => [:three]
13726 * One.instance_variables
13727 * # => [:@four]
13728 * One.class_variables
13729 * # => [:@@five]
13730 * global_variables.grep(/six/)
13731 * # => [:$six]
13732 * local_variables
13733 * # => [:seven]
13734 *
13735 * A +Symbol+ object differs from a String object in that
13736 * a +Symbol+ object represents an identifier, while a String object
13737 * represents text or data.
13738 *
13739 * == What's Here
13740 *
13741 * First, what's elsewhere. Class +Symbol+:
13742 *
13743 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
13744 * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
13745 *
13746 * Here, class +Symbol+ provides methods that are useful for:
13747 *
13748 * - {Querying}[rdoc-ref:Symbol@Methods+for+Querying]
13749 * - {Comparing}[rdoc-ref:Symbol@Methods+for+Comparing]
13750 * - {Converting}[rdoc-ref:Symbol@Methods+for+Converting]
13751 *
13752 * === Methods for Querying
13753 *
13754 * - ::all_symbols: Returns an array of the symbols currently in Ruby's symbol table.
13755 * - #=~: Returns the index of the first substring in symbol that matches a
13756 * given Regexp or other object; returns +nil+ if no match is found.
13757 * - #[], #slice : Returns a substring of symbol
13758 * determined by a given index, start/length, or range, or string.
13759 * - #empty?: Returns +true+ if +self.length+ is zero; +false+ otherwise.
13760 * - #encoding: Returns the Encoding object that represents the encoding
13761 * of symbol.
13762 * - #end_with?: Returns +true+ if symbol ends with
13763 * any of the given strings.
13764 * - #match: Returns a MatchData object if symbol
13765 * matches a given Regexp; +nil+ otherwise.
13766 * - #match?: Returns +true+ if symbol
13767 * matches a given Regexp; +false+ otherwise.
13768 * - #length, #size: Returns the number of characters in symbol.
13769 * - #start_with?: Returns +true+ if symbol starts with
13770 * any of the given strings.
13771 *
13772 * === Methods for Comparing
13773 *
13774 * - #<=>: Returns -1, 0, or 1 as a given symbol is smaller than, equal to,
13775 * or larger than symbol.
13776 * - #==, #===: Returns +true+ if a given symbol has the same content and
13777 * encoding.
13778 * - #casecmp: Ignoring case, returns -1, 0, or 1 as a given
13779 * symbol is smaller than, equal to, or larger than symbol.
13780 * - #casecmp?: Returns +true+ if symbol is equal to a given symbol
13781 * after Unicode case folding; +false+ otherwise.
13782 *
13783 * === Methods for Converting
13784 *
13785 * - #capitalize: Returns symbol with the first character upcased
13786 * and all other characters downcased.
13787 * - #downcase: Returns symbol with all characters downcased.
13788 * - #inspect: Returns the string representation of +self+ as a symbol literal.
13789 * - #name: Returns the frozen string corresponding to symbol.
13790 * - #succ, #next: Returns the symbol that is the successor to symbol.
13791 * - #swapcase: Returns symbol with all upcase characters downcased
13792 * and all downcase characters upcased.
13793 * - #to_proc: Returns a Proc object which responds to the method named by symbol.
13794 * - #to_s, #id2name: Returns the string corresponding to +self+.
13795 * - #to_sym, #intern: Returns +self+.
13796 * - #upcase: Returns symbol with all characters upcased.
13797 *
13798 */
13799
13800
13801/*
13802 * call-seq:
13803 * self == other -> true or false
13804 *
13805 * Returns whether +other+ is the same object as +self+.
13806 */
13807
13808#define sym_equal rb_obj_equal
13809
13810static int
13811sym_printable(const char *s, const char *send, rb_encoding *enc)
13812{
13813 while (s < send) {
13814 int n;
13815 int c = rb_enc_precise_mbclen(s, send, enc);
13816
13817 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
13818 n = MBCLEN_CHARFOUND_LEN(c);
13819 c = rb_enc_mbc_to_codepoint(s, send, enc);
13820 if (!rb_enc_isprint(c, enc)) return FALSE;
13821 s += n;
13822 }
13823 return TRUE;
13824}
13825
13826int
13827rb_str_symname_p(VALUE sym)
13828{
13829 rb_encoding *enc;
13830 const char *ptr;
13831 rb_len_t len;
13832 rb_encoding *resenc = rb_default_internal_encoding();
13833
13834 if (resenc == NULL) resenc = rb_default_external_encoding();
13835 enc = STR_ENC_GET(sym);
13836 ptr = RSTRING_PTR(sym);
13837 len = RSTRING_LEN(sym);
13838 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) || len != (rb_len_t)strlen(ptr) ||
13839 !rb_enc_symname2_p(ptr, len, enc) || !sym_printable(ptr, ptr + len, enc)) {
13840 return FALSE;
13841 }
13842 return TRUE;
13843}
13844
13845VALUE
13846rb_str_quote_unprintable(VALUE str)
13847{
13848 rb_encoding *enc;
13849 const char *ptr;
13850 rb_len_t len;
13851 rb_encoding *resenc;
13852
13853 Check_Type(str, T_STRING);
13854 resenc = rb_default_internal_encoding();
13855 if (resenc == NULL) resenc = rb_default_external_encoding();
13856 enc = STR_ENC_GET(str);
13857 ptr = RSTRING_PTR(str);
13858 len = RSTRING_LEN(str);
13859 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13860 !sym_printable(ptr, ptr + len, enc)) {
13861 return rb_str_escape(str);
13862 }
13863 return str;
13864}
13865
13866VALUE
13867rb_id_quote_unprintable(ID id)
13868{
13869 VALUE str = rb_id2str(id);
13870 if (!rb_str_symname_p(str)) {
13871 return rb_str_escape(str);
13872 }
13873 return str;
13874}
13875
13876/*
13877 * call-seq:
13878 * inspect -> string
13879 *
13880 * Returns a string representation of +self+ (including the leading colon):
13881 *
13882 * :foo.inspect # => ":foo"
13883 *
13884 * Related: Symbol#to_s, Symbol#name.
13885 *
13886 */
13887
13888static VALUE
13889sym_inspect(VALUE sym)
13890{
13891 VALUE str = rb_sym2str(sym);
13892 const char *ptr;
13893 rb_len_t len;
13894 char *dest;
13895
13896 if (!rb_str_symname_p(str)) {
13897 str = rb_str_inspect(str);
13898 len = RSTRING_LEN(str);
13899 rb_str_resize(str, len + 1);
13900 dest = RSTRING_PTR(str);
13901 memmove(dest + 1, dest, len);
13902 }
13903 else {
13904 rb_encoding *enc = STR_ENC_GET(str);
13905 VALUE orig_str = str;
13906
13907 len = RSTRING_LEN(orig_str);
13908 str = rb_enc_str_new(0, len + 1, enc);
13909
13910 // Get data pointer after allocation
13911 ptr = RSTRING_PTR(orig_str);
13912 dest = RSTRING_PTR(str);
13913 memcpy(dest + 1, ptr, len);
13914
13915 RB_GC_GUARD(orig_str);
13916 }
13917 dest[0] = ':';
13918
13920
13921 return str;
13922}
13923
13924VALUE
13926{
13927 return rb_sym2str(sym);
13928}
13929
13930VALUE
13931rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc)
13932{
13933 VALUE obj;
13934
13935 if (argc < 1) {
13936 rb_raise(rb_eArgError, "no receiver given");
13937 }
13938 obj = argv[0];
13939 return rb_funcall_with_block_kw(obj, mid, argc - 1, argv + 1, passed_proc, kw_splat);
13940}
13941
13942/*
13943 * call-seq:
13944 * succ
13945 *
13946 * Equivalent to <tt>self.to_s.succ.to_sym</tt>:
13947 *
13948 * :foo.succ # => :fop
13949 *
13950 * Related: String#succ.
13951 */
13952
13953static VALUE
13954sym_succ(VALUE sym)
13955{
13956 return rb_str_intern(rb_str_succ(rb_sym2str(sym)));
13957}
13958
13959/*
13960 * call-seq:
13961 * self <=> other -> -1, 0, 1, or nil
13962 *
13963 * Compares +self+ and +other+, using String#<=>.
13964 *
13965 * Returns:
13966 *
13967 * - <tt>self.to_s <=> other.to_s</tt>, if +other+ is a symbol.
13968 * - +nil+, otherwise.
13969 *
13970 * Examples:
13971 *
13972 * :bar <=> :foo # => -1
13973 * :foo <=> :foo # => 0
13974 * :foo <=> :bar # => 1
13975 * :foo <=> 'bar' # => nil
13976 *
13977 * \Class \Symbol includes module Comparable,
13978 * each of whose methods uses Symbol#<=> for comparison.
13979 *
13980 * Related: String#<=>.
13981 */
13982
13983static VALUE
13984sym_cmp(VALUE sym, VALUE other)
13985{
13986 if (!SYMBOL_P(other)) {
13987 return Qnil;
13988 }
13989 return rb_str_cmp_m(rb_sym2str(sym), rb_sym2str(other));
13990}
13991
13992/*
13993 * call-seq:
13994 * casecmp(object) -> -1, 0, 1, or nil
13995 *
13996 * :include: doc/symbol/casecmp.rdoc
13997 *
13998 */
13999
14000static VALUE
14001sym_casecmp(VALUE sym, VALUE other)
14002{
14003 if (!SYMBOL_P(other)) {
14004 return Qnil;
14005 }
14006 return str_casecmp(rb_sym2str(sym), rb_sym2str(other));
14007}
14008
14009/*
14010 * call-seq:
14011 * casecmp?(object) -> true, false, or nil
14012 *
14013 * :include: doc/symbol/casecmp_p.rdoc
14014 *
14015 */
14016
14017static VALUE
14018sym_casecmp_p(VALUE sym, VALUE other)
14019{
14020 if (!SYMBOL_P(other)) {
14021 return Qnil;
14022 }
14023 return str_casecmp_p(rb_sym2str(sym), rb_sym2str(other));
14024}
14025
14026/*
14027 * call-seq:
14028 * self =~ other -> integer or nil
14029 *
14030 * Equivalent to <tt>self.to_s =~ other</tt>,
14031 * including possible updates to global variables;
14032 * see String#=~.
14033 *
14034 */
14035
14036static VALUE
14037sym_match(VALUE sym, VALUE other)
14038{
14039 return rb_str_match(rb_sym2str(sym), other);
14040}
14041
14042/*
14043 * call-seq:
14044 * match(pattern, offset = 0) -> matchdata or nil
14045 * match(pattern, offset = 0) {|matchdata| } -> object
14046 *
14047 * Equivalent to <tt>self.to_s.match</tt>,
14048 * including possible updates to global variables;
14049 * see String#match.
14050 *
14051 */
14052
14053static VALUE
14054sym_match_m(int argc, VALUE *argv, VALUE sym)
14055{
14056 return rb_str_match_m(argc, argv, rb_sym2str(sym));
14057}
14058
14059/*
14060 * call-seq:
14061 * match?(pattern, offset) -> true or false
14062 *
14063 * Equivalent to <tt>sym.to_s.match?</tt>;
14064 * see String#match.
14065 *
14066 */
14067
14068static VALUE
14069sym_match_m_p(int argc, VALUE *argv, VALUE sym)
14070{
14071 return rb_str_match_m_p(argc, argv, sym);
14072}
14073
14074/*
14075 * call-seq:
14076 * self[offset] -> string or nil
14077 * self[offset, size] -> string or nil
14078 * self[range] -> string or nil
14079 * self[regexp, capture = 0] -> string or nil
14080 * self[substring] -> string or nil
14081 *
14082 * Equivalent to <tt>symbol.to_s[]</tt>; see String#[].
14083 *
14084 */
14085
14086static VALUE
14087sym_aref(int argc, VALUE *argv, VALUE sym)
14088{
14089 return rb_str_aref_m(argc, argv, rb_sym2str(sym));
14090}
14091
14092/*
14093 * call-seq:
14094 * length -> integer
14095 *
14096 * Equivalent to <tt>self.to_s.length</tt>; see String#length.
14097 */
14098
14099static VALUE
14100sym_length(VALUE sym)
14101{
14102 return rb_str_length(rb_sym2str(sym));
14103}
14104
14105/*
14106 * call-seq:
14107 * upcase(mapping) -> symbol
14108 *
14109 * Equivalent to <tt>sym.to_s.upcase.to_sym</tt>.
14110 *
14111 * See String#upcase.
14112 *
14113 */
14114
14115static VALUE
14116sym_upcase(int argc, VALUE *argv, VALUE sym)
14117{
14118 return rb_str_intern(rb_str_upcase(argc, argv, rb_sym2str(sym)));
14119}
14120
14121/*
14122 * call-seq:
14123 * downcase(mapping) -> symbol
14124 *
14125 * Equivalent to <tt>sym.to_s.downcase.to_sym</tt>.
14126 *
14127 * See String#downcase.
14128 *
14129 * Related: Symbol#upcase.
14130 *
14131 */
14132
14133static VALUE
14134sym_downcase(int argc, VALUE *argv, VALUE sym)
14135{
14136 return rb_str_intern(rb_str_downcase(argc, argv, rb_sym2str(sym)));
14137}
14138
14139/*
14140 * call-seq:
14141 * capitalize(mapping) -> symbol
14142 *
14143 * Equivalent to <tt>sym.to_s.capitalize.to_sym</tt>.
14144 *
14145 * See String#capitalize.
14146 *
14147 */
14148
14149static VALUE
14150sym_capitalize(int argc, VALUE *argv, VALUE sym)
14151{
14152 return rb_str_intern(rb_str_capitalize(argc, argv, rb_sym2str(sym)));
14153}
14154
14155/*
14156 * call-seq:
14157 * swapcase(mapping) -> symbol
14158 *
14159 * Equivalent to <tt>sym.to_s.swapcase.to_sym</tt>.
14160 *
14161 * See String#swapcase.
14162 *
14163 */
14164
14165static VALUE
14166sym_swapcase(int argc, VALUE *argv, VALUE sym)
14167{
14168 return rb_str_intern(rb_str_swapcase(argc, argv, rb_sym2str(sym)));
14169}
14170
14171/*
14172 * call-seq:
14173 * start_with?(*string_or_regexp) -> true or false
14174 *
14175 * Equivalent to <tt>self.to_s.start_with?</tt>; see String#start_with?.
14176 *
14177 */
14178
14179static VALUE
14180sym_start_with(int argc, VALUE *argv, VALUE sym)
14181{
14182 return rb_str_start_with(argc, argv, rb_sym2str(sym));
14183}
14184
14185/*
14186 * call-seq:
14187 * end_with?(*strings) -> true or false
14188 *
14189 *
14190 * Equivalent to <tt>self.to_s.end_with?</tt>; see String#end_with?.
14191 *
14192 */
14193
14194static VALUE
14195sym_end_with(int argc, VALUE *argv, VALUE sym)
14196{
14197 return rb_str_end_with(argc, argv, rb_sym2str(sym));
14198}
14199
14200/*
14201 * call-seq:
14202 * encoding -> encoding
14203 *
14204 * Equivalent to <tt>self.to_s.encoding</tt>; see String#encoding.
14205 *
14206 */
14207
14208static VALUE
14209sym_encoding(VALUE sym)
14210{
14211 return rb_obj_encoding(rb_sym2str(sym));
14212}
14213
14214static VALUE
14215string_for_symbol(VALUE name)
14216{
14217 if (!RB_TYPE_P(name, T_STRING)) {
14218 VALUE tmp = rb_check_string_type(name);
14219 if (NIL_P(tmp)) {
14220 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
14221 name);
14222 }
14223 name = tmp;
14224 }
14225 return name;
14226}
14227
14228ID
14230{
14231 if (SYMBOL_P(name)) {
14232 return SYM2ID(name);
14233 }
14234 name = string_for_symbol(name);
14235 return rb_intern_str(name);
14236}
14237
14238VALUE
14240{
14241 if (SYMBOL_P(name)) {
14242 return name;
14243 }
14244 name = string_for_symbol(name);
14245 return rb_str_intern(name);
14246}
14247
14248/*
14249 * call-seq:
14250 * Symbol.all_symbols -> array_of_symbols
14251 *
14252 * Returns an array of all symbols currently in Ruby's symbol table:
14253 *
14254 * Symbol.all_symbols.size # => 9334
14255 * Symbol.all_symbols.take(3) # => [:!, :"\"", :"#"]
14256 *
14257 */
14258
14259static VALUE
14260sym_all_symbols(VALUE _)
14261{
14262 return rb_sym_all_symbols();
14263}
14264
14265VALUE
14266rb_str_to_interned_str(VALUE str)
14267{
14268 return rb_fstring(str);
14269}
14270
14271VALUE
14273{
14274 struct RString fake_str = {RBASIC_INIT};
14275 int encidx = ENCINDEX_US_ASCII;
14276 int coderange = ENC_CODERANGE_7BIT;
14277 if (len > 0 && search_nonascii(ptr, ptr + len)) {
14278 encidx = ENCINDEX_ASCII_8BIT;
14279 coderange = ENC_CODERANGE_VALID;
14280 }
14281 VALUE str = setup_fake_str(&fake_str, ptr, len, encidx);
14282 ENC_CODERANGE_SET(str, coderange);
14283 return register_fstring(str, true, false);
14284}
14285
14286VALUE
14288{
14289 return rb_interned_str(ptr, strlen(ptr));
14290}
14291
14292VALUE
14294{
14295 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14296 rb_enc_autoload(enc);
14297 }
14298
14299 struct RString fake_str = {RBASIC_INIT};
14300 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, false);
14301}
14302
14303VALUE
14304rb_enc_literal_str(const char *ptr, rb_len_t len, rb_encoding *enc)
14305{
14306 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14307 rb_enc_autoload(enc);
14308 }
14309
14310 struct RString fake_str = {RBASIC_INIT};
14311 VALUE str = register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true);
14312 RUBY_ASSERT(RB_OBJ_SHAREABLE_P(str) && (rb_gc_verify_shareable(str), 1));
14313 return str;
14314}
14315
14316VALUE
14318{
14319 return rb_enc_interned_str(ptr, strlen(ptr), enc);
14320}
14321
14322#if USE_YJIT || USE_ZJIT
14323void
14324rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint)
14325{
14326 if (RB_LIKELY(ENCODING_GET_INLINED(str) == rb_ascii8bit_encindex())) {
14327 ssize_t code = RB_NUM2SSIZE(codepoint);
14328
14329 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14330 rb_str_buf_cat_byte(str, (char) code);
14331 return;
14332 }
14333 }
14334
14335 rb_str_concat(str, codepoint);
14336}
14337#endif
14338
14339static int
14340fstring_set_class_i(VALUE *str, void *data)
14341{
14342 RBASIC_SET_CLASS(*str, rb_cString);
14343
14344 return ST_CONTINUE;
14345}
14346
14347void
14348Init_String(void)
14349{
14350 rb_cString = rb_define_class("String", rb_cObject);
14351
14352 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14353
14355 rb_define_alloc_func(rb_cString, empty_str_alloc);
14356 rb_define_singleton_method(rb_cString, "new", rb_str_s_new, -1);
14357 rb_define_singleton_method(rb_cString, "try_convert", rb_str_s_try_convert, 1);
14358 rb_define_method(rb_cString, "initialize", rb_str_init, -1);
14360 rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1);
14361 rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
14364 rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
14365 rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
14366 rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
14367 rb_define_method(rb_cString, "casecmp?", rb_str_casecmp_p, 1);
14370 rb_define_method(rb_cString, "%", rb_str_format_m, 1);
14371 rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
14372 rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
14373 rb_define_method(rb_cString, "insert", rb_str_insert, 2);
14376 rb_define_method(rb_cString, "bytesize", rb_str_bytesize, 0);
14377 rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
14378 rb_define_method(rb_cString, "=~", rb_str_match, 1);
14379 rb_define_method(rb_cString, "match", rb_str_match_m, -1);
14380 rb_define_method(rb_cString, "match?", rb_str_match_m_p, -1);
14382 rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0);
14384 rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0);
14385 rb_define_method(rb_cString, "upto", rb_str_upto, -1);
14386 rb_define_method(rb_cString, "index", rb_str_index_m, -1);
14387 rb_define_method(rb_cString, "byteindex", rb_str_byteindex_m, -1);
14388 rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1);
14389 rb_define_method(rb_cString, "byterindex", rb_str_byterindex_m, -1);
14390 rb_define_method(rb_cString, "clear", rb_str_clear, 0);
14391 rb_define_method(rb_cString, "chr", rb_str_chr, 0);
14392 rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
14393 rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);
14394 rb_define_method(rb_cString, "bit_get", rb_str_bit_get, -1);
14395 rb_define_method(rb_cString, "bit_set?", rb_str_bit_set_p, -1);
14396 rb_define_method(rb_cString, "bit_set", rb_str_bit_set, -1);
14397 rb_define_method(rb_cString, "bit_clear", rb_str_bit_clear, -1);
14398 rb_define_method(rb_cString, "bit_flip", rb_str_bit_flip, -1);
14399 rb_define_method(rb_cString, "bit_count", rb_str_bit_count, -1);
14400 rb_define_method(rb_cString, "bitwise_not", rb_str_bitwise_not, 0);
14401 rb_define_method(rb_cString, "bitwise_not!", rb_str_bitwise_not_bang, 0);
14402 rb_define_method(rb_cString, "bitwise_and", rb_str_bitwise_and, 1);
14403 rb_define_method(rb_cString, "bitwise_and!", rb_str_bitwise_and_bang, 1);
14404 rb_define_method(rb_cString, "bitwise_or", rb_str_bitwise_or, 1);
14405 rb_define_method(rb_cString, "bitwise_or!", rb_str_bitwise_or_bang, 1);
14406 rb_define_method(rb_cString, "bitwise_xor", rb_str_bitwise_xor, 1);
14407 rb_define_method(rb_cString, "bitwise_xor!", rb_str_bitwise_xor_bang, 1);
14408 rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);
14409 rb_define_method(rb_cString, "bytesplice", rb_str_bytesplice, -1);
14410 rb_define_method(rb_cString, "scrub", str_scrub, -1);
14411 rb_define_method(rb_cString, "scrub!", str_scrub_bang, -1);
14413 rb_define_method(rb_cString, "+@", str_uplus, 0);
14414 rb_define_method(rb_cString, "-@", str_uminus, 0);
14415 rb_define_method(rb_cString, "dup", rb_str_dup_m, 0);
14416 rb_define_alias(rb_cString, "dedup", "-@");
14417
14418 rb_define_method(rb_cString, "to_i", rb_str_to_i, -1);
14419 rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);
14420 rb_define_method(rb_cString, "to_s", rb_str_to_s, 0);
14421 rb_define_method(rb_cString, "to_str", rb_str_to_s, 0);
14424 rb_define_method(rb_cString, "undump", str_undump, 0);
14425
14426 sym_ascii = ID2SYM(rb_intern_const("ascii"));
14427 sym_turkic = ID2SYM(rb_intern_const("turkic"));
14428 sym_lithuanian = ID2SYM(rb_intern_const("lithuanian"));
14429 sym_fold = ID2SYM(rb_intern_const("fold"));
14430
14431 rb_define_method(rb_cString, "upcase", rb_str_upcase, -1);
14432 rb_define_method(rb_cString, "downcase", rb_str_downcase, -1);
14433 rb_define_method(rb_cString, "capitalize", rb_str_capitalize, -1);
14434 rb_define_method(rb_cString, "swapcase", rb_str_swapcase, -1);
14435
14436 rb_define_method(rb_cString, "upcase!", rb_str_upcase_bang, -1);
14437 rb_define_method(rb_cString, "downcase!", rb_str_downcase_bang, -1);
14438 rb_define_method(rb_cString, "capitalize!", rb_str_capitalize_bang, -1);
14439 rb_define_method(rb_cString, "swapcase!", rb_str_swapcase_bang, -1);
14440
14441 rb_define_method(rb_cString, "hex", rb_str_hex, 0);
14442 rb_define_method(rb_cString, "oct", rb_str_oct, 0);
14443 rb_define_method(rb_cString, "split", rb_str_split_m, -1);
14444 rb_define_method(rb_cString, "lines", rb_str_lines, -1);
14445 rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
14446 rb_define_method(rb_cString, "chars", rb_str_chars, 0);
14447 rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
14448 rb_define_method(rb_cString, "grapheme_clusters", rb_str_grapheme_clusters, 0);
14449 rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
14450 rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
14451 rb_define_method(rb_cString, "concat", rb_str_concat_multi, -1);
14452 rb_define_method(rb_cString, "append_as_bytes", rb_str_append_as_bytes, -1);
14454 rb_define_method(rb_cString, "prepend", rb_str_prepend_multi, -1);
14455 rb_define_method(rb_cString, "crypt", rb_str_crypt, 1);
14456 rb_define_method(rb_cString, "intern", rb_str_intern, 0); /* in symbol.c */
14457 rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); /* in symbol.c */
14458 rb_define_method(rb_cString, "ord", rb_str_ord, 0);
14459
14460 rb_define_method(rb_cString, "include?", rb_str_include, 1);
14461 rb_define_method(rb_cString, "start_with?", rb_str_start_with, -1);
14462 rb_define_method(rb_cString, "end_with?", rb_str_end_with, -1);
14463
14464 rb_define_method(rb_cString, "scan", rb_str_scan, 1);
14465
14466 rb_define_method(rb_cString, "ljust", rb_str_ljust, -1);
14467 rb_define_method(rb_cString, "rjust", rb_str_rjust, -1);
14468 rb_define_method(rb_cString, "center", rb_str_center, -1);
14469
14470 rb_define_method(rb_cString, "sub", rb_str_sub, -1);
14471 rb_define_method(rb_cString, "gsub", rb_str_gsub, -1);
14472 rb_define_method(rb_cString, "chop", rb_str_chop, 0);
14473 rb_define_method(rb_cString, "chomp", rb_str_chomp, -1);
14474 rb_define_method(rb_cString, "strip", rb_str_strip, -1);
14475 rb_define_method(rb_cString, "lstrip", rb_str_lstrip, -1);
14476 rb_define_method(rb_cString, "rstrip", rb_str_rstrip, -1);
14477 rb_define_method(rb_cString, "delete_prefix", rb_str_delete_prefix, 1);
14478 rb_define_method(rb_cString, "delete_suffix", rb_str_delete_suffix, 1);
14479
14480 rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1);
14481 rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1);
14482 rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0);
14483 rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1);
14484 rb_define_method(rb_cString, "strip!", rb_str_strip_bang, -1);
14485 rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, -1);
14486 rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, -1);
14487 rb_define_method(rb_cString, "delete_prefix!", rb_str_delete_prefix_bang, 1);
14488 rb_define_method(rb_cString, "delete_suffix!", rb_str_delete_suffix_bang, 1);
14489
14490 rb_define_method(rb_cString, "tr", rb_str_tr, -1);
14491 rb_define_method(rb_cString, "tr_s", rb_str_tr_s, 2);
14492 rb_define_method(rb_cString, "delete", rb_str_delete, -1);
14493 rb_define_method(rb_cString, "squeeze", rb_str_squeeze, -1);
14494 rb_define_method(rb_cString, "count", rb_str_count, -1);
14495
14496 rb_define_method(rb_cString, "tr!", rb_str_tr_bang, -1);
14497 rb_define_method(rb_cString, "tr_s!", rb_str_tr_s_bang, 2);
14498 rb_define_method(rb_cString, "delete!", rb_str_delete_bang, -1);
14499 rb_define_method(rb_cString, "squeeze!", rb_str_squeeze_bang, -1);
14500
14501 rb_define_method(rb_cString, "each_line", rb_str_each_line, -1);
14502 rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0);
14503 rb_define_method(rb_cString, "each_char", rb_str_each_char, 0);
14504 rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0);
14505 rb_define_method(rb_cString, "each_grapheme_cluster", rb_str_each_grapheme_cluster, 0);
14506
14507 rb_define_method(rb_cString, "sum", rb_str_sum, -1);
14508
14509 rb_define_method(rb_cString, "slice", rb_str_aref_m, -1);
14510 rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1);
14511
14512 rb_define_method(rb_cString, "partition", rb_str_partition, 1);
14513 rb_define_method(rb_cString, "rpartition", rb_str_rpartition, 1);
14514
14515 rb_define_method(rb_cString, "encoding", rb_obj_encoding, 0); /* in encoding.c */
14516 rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1);
14517 rb_define_method(rb_cString, "b", rb_str_b, 0);
14518
14519 /* define UnicodeNormalize module here so that we don't have to look it up */
14520 mUnicodeNormalize = rb_define_module("UnicodeNormalize");
14521 id_normalize = rb_intern_const("normalize");
14522 id_normalized_p = rb_intern_const("normalized?");
14523
14524 rb_define_method(rb_cString, "unicode_normalize", rb_str_unicode_normalize, -1);
14525 rb_define_method(rb_cString, "unicode_normalize!", rb_str_unicode_normalize_bang, -1);
14526 rb_define_method(rb_cString, "unicode_normalized?", rb_str_unicode_normalized_p, -1);
14527
14528 rb_fs = Qnil;
14529 rb_define_hooked_variable("$;", &rb_fs, 0, rb_fs_setter);
14530 rb_define_hooked_variable("$-F", &rb_fs, 0, rb_fs_setter);
14531 rb_gc_register_address(&rb_fs);
14532
14533 rb_cSymbol = rb_define_class("Symbol", rb_cObject);
14537 rb_define_singleton_method(rb_cSymbol, "all_symbols", sym_all_symbols, 0);
14538
14539 rb_define_method(rb_cSymbol, "==", sym_equal, 1);
14540 rb_define_method(rb_cSymbol, "===", sym_equal, 1);
14541 rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
14542 rb_define_method(rb_cSymbol, "to_proc", rb_sym_to_proc, 0); /* in proc.c */
14543 rb_define_method(rb_cSymbol, "succ", sym_succ, 0);
14544 rb_define_method(rb_cSymbol, "next", sym_succ, 0);
14545
14546 rb_define_method(rb_cSymbol, "<=>", sym_cmp, 1);
14547 rb_define_method(rb_cSymbol, "casecmp", sym_casecmp, 1);
14548 rb_define_method(rb_cSymbol, "casecmp?", sym_casecmp_p, 1);
14549 rb_define_method(rb_cSymbol, "=~", sym_match, 1);
14550
14551 rb_define_method(rb_cSymbol, "[]", sym_aref, -1);
14552 rb_define_method(rb_cSymbol, "slice", sym_aref, -1);
14553 rb_define_method(rb_cSymbol, "length", sym_length, 0);
14554 rb_define_method(rb_cSymbol, "size", sym_length, 0);
14555 rb_define_method(rb_cSymbol, "match", sym_match_m, -1);
14556 rb_define_method(rb_cSymbol, "match?", sym_match_m_p, -1);
14557
14558 rb_define_method(rb_cSymbol, "upcase", sym_upcase, -1);
14559 rb_define_method(rb_cSymbol, "downcase", sym_downcase, -1);
14560 rb_define_method(rb_cSymbol, "capitalize", sym_capitalize, -1);
14561 rb_define_method(rb_cSymbol, "swapcase", sym_swapcase, -1);
14562
14563 rb_define_method(rb_cSymbol, "start_with?", sym_start_with, -1);
14564 rb_define_method(rb_cSymbol, "end_with?", sym_end_with, -1);
14565
14566 rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0);
14567}
14568
14569#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:1249
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:1736
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3060
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2863
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:3350
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:3139
#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:405
#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:33
#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:402
#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:400
#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:406
#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:34
#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:407
#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:4053
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:664
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2274
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:2292
VALUE rb_obj_frozen_p(VALUE obj)
Same as RB_OBJ_FROZEN(), but returns Qtrue/Qfalse instead of #bool.
Definition object.c:1322
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:3661
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:240
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:562
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:912
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1315
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:3347
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:2430
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1393
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:1258
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:858
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:1399
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:1277
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:1189
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:1498
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:3873
int rb_enc_str_asciionly_p(VALUE str)
Queries if the passed string is "ASCII only".
Definition string.c:1002
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:14293
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:14317
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:3148
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:1148
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:1106
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:1235
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:737
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:200
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
Definition vm.c:2166
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:2172
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:1444
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4624
VALUE rb_reg_match(VALUE re, VALUE str)
This is the match operator.
Definition re.c:4118
void rb_match_busy(VALUE md)
Asserts that the given MatchData is "occupied".
Definition re.c:1688
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
Definition re.c:2128
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:1474
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:2841
void rb_str_free(VALUE str)
Destroys the given string for no reason.
Definition string.c:1817
rb_len_t rb_str_offset(VALUE str, rb_len_t pos)
"Inverse" of rb_str_sublen().
Definition string.c:3176
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:3291
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:2517
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:1563
VALUE rb_str_plus(VALUE lhs, VALUE rhs)
Generates a new string, concatenating the former to the latter.
Definition string.c:2581
#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:3938
VALUE rb_str_tmp_new(rb_len_t len)
Allocates a "temporary" string.
Definition string.c:1811
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
Definition string.c:13925
VALUE rb_str_times(VALUE str, VALUE num)
Repetition of a string.
Definition string.c:2655
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
Definition string.c:5481
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4300
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:1252
#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:1853
#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:1037
rb_len_t rb_str_sublen(VALUE str, rb_len_t pos)
Byte offset to character offset conversion.
Definition string.c:3223
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:1450
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1569
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
Definition string.c:3525
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2052
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4286
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:13240
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
Definition string.c:3706
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:2070
#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:1223
#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:1767
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:6700
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:1598
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:14287
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:1480
VALUE rb_str_drop_bytes(VALUE str, rb_len_t len)
Shrinks the given string for the given number of bytes.
Definition string.c:5883
#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:3904
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:4407
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:1641
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:5968
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:8237
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2887
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:3388
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4354
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:4174
int rb_str_comparable(VALUE str1, VALUE str2)
Checks if two strings are comparable each other or not.
Definition string.c:4329
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:1246
#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:14272
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:3880
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3416
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:3299
VALUE rb_str_scrub(VALUE str, VALUE repl)
"Cleanses" the string.
Definition string.c:13298
#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:1783
#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:1462
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3072
#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:3507
#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:8354
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
Definition string.c:2531
#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:10896
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:1916
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:2150
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
Definition variable.c:2210
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3715
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1865
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:14239
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:14229
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:2057
VALUE rb_reg_regcomp(VALUE str)
Creates a new instance of rb_cRegexp.
Definition re.c:3791
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt)
Formats a string.
Definition sprintf.c:985
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1403
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:373
#define ALLOCA_N(type, n)
Definition memory.h:293
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:361
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:168
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
#define RMATCH(obj)
Convenient casting macro.
Definition rmatch.h:37
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:1492
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:3043
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:2906
#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:1486
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:2919
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:1844
#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:1529
#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:9278
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:142
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
Definition value.h:156
#define RB_LEN_MIN
Minimum possible value that a rb_len_t can take.
Definition value.h:159
unsigned long rb_ulen_t
An unsigned integer type that has the same width with rb_len_t.
Definition value.h:145
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