Ruby 4.0.9p0 (2026-10-23 revision 3e93b23afcec3433f6aecc34b5d832799d754238)
string.c
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/compar.h"
30#include "internal/compilers.h"
31#include "internal/concurrent_set.h"
32#include "internal/encoding.h"
33#include "internal/error.h"
34#include "internal/gc.h"
35#include "internal/hash.h"
36#include "internal/numeric.h"
37#include "internal/object.h"
38#include "internal/proc.h"
39#include "internal/re.h"
40#include "internal/sanitizers.h"
41#include "internal/string.h"
42#include "internal/transcode.h"
43#include "probes.h"
44#include "ruby/encoding.h"
45#include "ruby/re.h"
46#include "ruby/thread.h"
47#include "ruby/util.h"
48#include "ruby/ractor.h"
49#include "ruby_assert.h"
50#include "shape.h"
51#include "vm_sync.h"
53
54#if defined HAVE_CRYPT_R
55# if defined HAVE_CRYPT_H
56# include <crypt.h>
57# endif
58#elif !defined HAVE_CRYPT
59# include "missing/crypt.h"
60# define HAVE_CRYPT_R 1
61#endif
62
63#define BEG(no) (regs->beg[(no)])
64#define END(no) (regs->end[(no)])
65
66#undef rb_str_new
67#undef rb_usascii_str_new
68#undef rb_utf8_str_new
69#undef rb_enc_str_new
70#undef rb_str_new_cstr
71#undef rb_usascii_str_new_cstr
72#undef rb_utf8_str_new_cstr
73#undef rb_enc_str_new_cstr
74#undef rb_external_str_new_cstr
75#undef rb_locale_str_new_cstr
76#undef rb_str_dup_frozen
77#undef rb_str_buf_new_cstr
78#undef rb_str_buf_cat
79#undef rb_str_buf_cat2
80#undef rb_str_cat2
81#undef rb_str_cat_cstr
82#undef rb_fstring_cstr
83
86
87/* Flags of RString
88 *
89 * 0: STR_SHARED (equal to ELTS_SHARED)
90 * The string is shared. The buffer this string points to is owned by
91 * another string (the shared root).
92 * 1: RSTRING_NOEMBED
93 * The string is not embedded. When a string is embedded, the contents
94 * follow the header. When a string is not embedded, the contents is
95 * on a separately allocated buffer.
96 * 2: STR_CHILLED_LITERAL (will be frozen in a future version)
97 * The string was allocated as a literal in a file without an explicit `frozen_string_literal` comment.
98 * It emits a deprecation warning when mutated for the first time.
99 * 3: STR_CHILLED_SYMBOL_TO_S (will be frozen in a future version)
100 * The string was allocated by the `Symbol#to_s` method.
101 * It emits a deprecation warning when mutated for the first time.
102 * 4: STR_PRECOMPUTED_HASH
103 * The string is embedded and has its precomputed hashcode stored
104 * after the terminator.
105 * 5: STR_SHARED_ROOT
106 * Other strings may point to the contents of this string. When this
107 * flag is set, STR_SHARED must not be set.
108 * 6: STR_BORROWED
109 * When RSTRING_NOEMBED is set and klass is 0, this string is unsafe
110 * to be unshared by rb_str_tmp_frozen_release.
111 * 7: STR_TMPLOCK
112 * The pointer to the buffer is passed to a system call such as
113 * read(2). Any modification and realloc is prohibited.
114 * 8-9: ENC_CODERANGE
115 * Stores the coderange of the string.
116 * 10-16: ENCODING
117 * Stores the encoding of the string.
118 * 17: RSTRING_FSTR
119 * The string is a fstring. The string is deduplicated in the fstring
120 * table.
121 * 18: STR_NOFREE
122 * Do not free this string's buffer when the string is reclaimed
123 * by the garbage collector. Used for when the string buffer is a C
124 * string literal.
125 * 19: STR_FAKESTR
126 * The string is not allocated or managed by the garbage collector.
127 * Typically, the string object header (struct RString) is temporarily
128 * allocated on C stack.
129 */
130
131#define RUBY_MAX_CHAR_LEN 16
132#define STR_PRECOMPUTED_HASH FL_USER4
133#define STR_SHARED_ROOT FL_USER5
134#define STR_BORROWED FL_USER6
135#define STR_TMPLOCK FL_USER7
136#define STR_NOFREE FL_USER18
137#define STR_FAKESTR FL_USER19
138
139#define STR_SET_NOEMBED(str) do {\
140 FL_SET((str), STR_NOEMBED);\
141 FL_UNSET((str), STR_SHARED | STR_SHARED_ROOT | STR_BORROWED);\
142} while (0)
143#define STR_SET_EMBED(str) FL_UNSET((str), STR_NOEMBED | STR_SHARED | STR_NOFREE)
144
145#define STR_SET_LEN(str, n) do { \
146 RSTRING(str)->len = (n); \
147} while (0)
148
149static inline bool
150str_encindex_fastpath(int encindex)
151{
152 // The overwhelming majority of strings are in one of these 3 encodings.
153 switch (encindex) {
154 case ENCINDEX_ASCII_8BIT:
155 case ENCINDEX_UTF_8:
156 case ENCINDEX_US_ASCII:
157 return true;
158 default:
159 return false;
160 }
161}
162
163static inline bool
164str_enc_fastpath(VALUE str)
165{
166 return str_encindex_fastpath(ENCODING_GET_INLINED(str));
167}
168
169#define TERM_LEN(str) (str_enc_fastpath(str) ? 1 : rb_enc_mbminlen(rb_enc_from_index(ENCODING_GET(str))))
170#define TERM_FILL(ptr, termlen) do {\
171 char *const term_fill_ptr = (ptr);\
172 const int term_fill_len = (termlen);\
173 *term_fill_ptr = '\0';\
174 if (UNLIKELY(term_fill_len > 1))\
175 memset(term_fill_ptr, 0, term_fill_len);\
176} while (0)
177
178#define RESIZE_CAPA(str,capacity) do {\
179 const int termlen = TERM_LEN(str);\
180 RESIZE_CAPA_TERM(str,capacity,termlen);\
181} while (0)
182#define RESIZE_CAPA_TERM(str,capacity,termlen) do {\
183 if (STR_EMBED_P(str)) {\
184 if (str_embed_capa(str) < capacity + termlen) {\
185 char *const tmp = ALLOC_N(char, (size_t)(capacity) + (termlen));\
186 const long tlen = RSTRING_LEN(str);\
187 memcpy(tmp, RSTRING_PTR(str), tlen);\
188 RSTRING(str)->as.heap.ptr = tmp;\
189 RSTRING(str)->len = tlen;\
190 STR_SET_NOEMBED(str);\
191 RSTRING(str)->as.heap.aux.capa = (capacity);\
192 }\
193 }\
194 else {\
195 RUBY_ASSERT(!FL_TEST((str), STR_SHARED)); \
196 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char, \
197 (size_t)(capacity) + (termlen), STR_HEAP_SIZE(str)); \
198 RSTRING(str)->as.heap.aux.capa = (capacity);\
199 }\
200} while (0)
201
202#define STR_SET_SHARED(str, shared_str) do { \
203 if (!FL_TEST(str, STR_FAKESTR)) { \
204 RUBY_ASSERT(RSTRING_PTR(shared_str) <= RSTRING_PTR(str)); \
205 RUBY_ASSERT(RSTRING_PTR(str) <= RSTRING_PTR(shared_str) + RSTRING_LEN(shared_str)); \
206 RB_OBJ_WRITE((str), &RSTRING(str)->as.heap.aux.shared, (shared_str)); \
207 FL_SET((str), STR_SHARED); \
208 FL_SET((shared_str), STR_SHARED_ROOT); \
209 if (RBASIC_CLASS((shared_str)) == 0) /* for CoW-friendliness */ \
210 FL_SET_RAW((shared_str), STR_BORROWED); \
211 } \
212} while (0)
213
214#define STR_HEAP_PTR(str) (RSTRING(str)->as.heap.ptr)
215#define STR_HEAP_SIZE(str) ((size_t)RSTRING(str)->as.heap.aux.capa + TERM_LEN(str))
216/* TODO: include the terminator size in capa. */
217
218#define STR_ENC_GET(str) get_encoding(str)
219
220#if !defined SHARABLE_MIDDLE_SUBSTRING
221# define SHARABLE_MIDDLE_SUBSTRING 0
222#endif
223#if !SHARABLE_MIDDLE_SUBSTRING
224#define SHARABLE_SUBSTRING_P(beg, len, end) ((beg) + (len) == (end))
225#else
226#define SHARABLE_SUBSTRING_P(beg, len, end) 1
227#endif
228
229
230static inline long
231str_embed_capa(VALUE str)
232{
233 return rb_gc_obj_slot_size(str) - offsetof(struct RString, as.embed.ary);
234}
235
236bool
237rb_str_reembeddable_p(VALUE str)
238{
239 return !FL_TEST(str, STR_NOFREE|STR_SHARED_ROOT|STR_SHARED);
240}
241
242static inline size_t
243rb_str_embed_size(long capa, long termlen)
244{
245 size_t size = offsetof(struct RString, as.embed.ary) + capa + termlen;
246 if (size < sizeof(struct RString)) size = sizeof(struct RString);
247 return size;
248}
249
250size_t
251rb_str_size_as_embedded(VALUE str)
252{
253 size_t real_size;
254 if (STR_EMBED_P(str)) {
255 size_t capa = RSTRING(str)->len;
256 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) capa += sizeof(st_index_t);
257
258 real_size = rb_str_embed_size(capa, TERM_LEN(str));
259 }
260 /* if the string is not currently embedded, but it can be embedded, how
261 * much space would it require */
262 else if (rb_str_reembeddable_p(str)) {
263 size_t capa = RSTRING(str)->as.heap.aux.capa;
264 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) capa += sizeof(st_index_t);
265
266 real_size = rb_str_embed_size(capa, TERM_LEN(str));
267 }
268 else {
269 real_size = sizeof(struct RString);
270 }
271
272 return real_size;
273}
274
275static inline bool
276STR_EMBEDDABLE_P(long len, long termlen)
277{
278 return rb_gc_size_allocatable_p(rb_str_embed_size(len, termlen));
279}
280
281static VALUE str_replace_shared_without_enc(VALUE str2, VALUE str);
282static VALUE str_new_frozen(VALUE klass, VALUE orig);
283static VALUE str_new_frozen_buffer(VALUE klass, VALUE orig, int copy_encoding);
284static VALUE str_new_static(VALUE klass, const char *ptr, long len, int encindex);
285static VALUE str_new(VALUE klass, const char *ptr, long len);
286static void str_make_independent_expand(VALUE str, long len, long expand, const int termlen);
287static inline void str_modifiable(VALUE str);
288static VALUE rb_str_downcase(int argc, VALUE *argv, VALUE str);
289static inline VALUE str_alloc_embed(VALUE klass, size_t capa);
290
291static inline void
292str_make_independent(VALUE str)
293{
294 long len = RSTRING_LEN(str);
295 int termlen = TERM_LEN(str);
296 str_make_independent_expand((str), len, 0L, termlen);
297}
298
299static inline int str_dependent_p(VALUE str);
300
301void
302rb_str_make_independent(VALUE str)
303{
304 if (str_dependent_p(str)) {
305 str_make_independent(str);
306 }
307}
308
309void
310rb_str_make_embedded(VALUE str)
311{
312 RUBY_ASSERT(rb_str_reembeddable_p(str));
313 RUBY_ASSERT(!STR_EMBED_P(str));
314
315 char *buf = RSTRING(str)->as.heap.ptr;
316 long len = RSTRING(str)->len;
317
318 STR_SET_EMBED(str);
319 STR_SET_LEN(str, len);
320
321 if (len > 0) {
322 memcpy(RSTRING_PTR(str), buf, len);
323 ruby_xfree(buf);
324 }
325
326 TERM_FILL(RSTRING(str)->as.embed.ary + len, TERM_LEN(str));
327}
328
329void
330rb_debug_rstring_null_ptr(const char *func)
331{
332 fprintf(stderr, "%s is returning NULL!! "
333 "SIGSEGV is highly expected to follow immediately.\n"
334 "If you could reproduce, attach your debugger here, "
335 "and look at the passed string.\n",
336 func);
337}
338
339/* symbols for [up|down|swap]case/capitalize options */
340static VALUE sym_ascii, sym_turkic, sym_lithuanian, sym_fold;
341
342static rb_encoding *
343get_encoding(VALUE str)
344{
345 return rb_enc_from_index(ENCODING_GET(str));
346}
347
348static void
349mustnot_broken(VALUE str)
350{
351 if (is_broken_string(str)) {
352 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str)));
353 }
354}
355
356static void
357mustnot_wchar(VALUE str)
358{
359 rb_encoding *enc = STR_ENC_GET(str);
360 if (rb_enc_mbminlen(enc) > 1) {
361 rb_raise(rb_eArgError, "wide char encoding: %s", rb_enc_name(enc));
362 }
363}
364
365static VALUE register_fstring(VALUE str, bool copy, bool force_precompute_hash);
366
367#if SIZEOF_LONG == SIZEOF_VOIDP
368#define PRECOMPUTED_FAKESTR_HASH 1
369#else
370#endif
371
372static inline bool
373BARE_STRING_P(VALUE str)
374{
375 return RBASIC_CLASS(str) == rb_cString && !rb_shape_obj_has_ivars(str);
376}
377
378static inline st_index_t
379str_do_hash(VALUE str)
380{
381 st_index_t h = rb_memhash((const void *)RSTRING_PTR(str), RSTRING_LEN(str));
382 int e = RSTRING_LEN(str) ? ENCODING_GET(str) : 0;
383 if (e && !is_ascii_string(str)) {
384 h = rb_hash_end(rb_hash_uint32(h, (uint32_t)e));
385 }
386 return h;
387}
388
389static VALUE
390str_store_precomputed_hash(VALUE str, st_index_t hash)
391{
392 RUBY_ASSERT(!FL_TEST_RAW(str, STR_PRECOMPUTED_HASH));
393 RUBY_ASSERT(STR_EMBED_P(str));
394
395#if RUBY_DEBUG
396 size_t used_bytes = (RSTRING_LEN(str) + TERM_LEN(str));
397 size_t free_bytes = str_embed_capa(str) - used_bytes;
398 RUBY_ASSERT(free_bytes >= sizeof(st_index_t));
399#endif
400
401 memcpy(RSTRING_END(str) + TERM_LEN(str), &hash, sizeof(hash));
402
403 FL_SET(str, STR_PRECOMPUTED_HASH);
404
405 return str;
406}
407
408VALUE
409rb_fstring(VALUE str)
410{
411 VALUE fstr;
412 int bare;
413
414 Check_Type(str, T_STRING);
415
416 if (FL_TEST(str, RSTRING_FSTR))
417 return str;
418
419 bare = BARE_STRING_P(str);
420 if (!bare) {
421 if (STR_EMBED_P(str)) {
422 OBJ_FREEZE(str);
423 return str;
424 }
425
426 if (FL_TEST_RAW(str, STR_SHARED_ROOT | STR_SHARED) == STR_SHARED_ROOT) {
428 return str;
429 }
430 }
431
432 if (!FL_TEST_RAW(str, FL_FREEZE | STR_NOFREE | STR_CHILLED))
433 rb_str_resize(str, RSTRING_LEN(str));
434
435 fstr = register_fstring(str, false, false);
436
437 if (!bare) {
438 str_replace_shared_without_enc(str, fstr);
439 OBJ_FREEZE(str);
440 return str;
441 }
442 return fstr;
443}
444
445static VALUE fstring_table_obj;
446
447static VALUE
448fstring_concurrent_set_hash(VALUE str)
449{
450#ifdef PRECOMPUTED_FAKESTR_HASH
451 st_index_t h;
452 if (FL_TEST_RAW(str, STR_FAKESTR)) {
453 // register_fstring precomputes the hash and stores it in capa for fake strings
454 h = (st_index_t)RSTRING(str)->as.heap.aux.capa;
455 }
456 else {
457 h = rb_str_hash(str);
458 }
459 // rb_str_hash doesn't include the encoding for ascii only strings, so
460 // we add it to avoid common collisions between `:sym.name` (ASCII) and `"sym"` (UTF-8)
461 return (VALUE)rb_hash_end(rb_hash_uint32(h, (uint32_t)ENCODING_GET_INLINED(str)));
462#else
463 return (VALUE)rb_str_hash(str);
464#endif
465}
466
467static bool
468fstring_concurrent_set_cmp(VALUE a, VALUE b)
469{
470 long alen, blen;
471 const char *aptr, *bptr;
472
473 RUBY_ASSERT(RB_TYPE_P(a, T_STRING));
474 RUBY_ASSERT(RB_TYPE_P(b, T_STRING));
475
476 RSTRING_GETMEM(a, aptr, alen);
477 RSTRING_GETMEM(b, bptr, blen);
478 return (alen == blen &&
479 ENCODING_GET(a) == ENCODING_GET(b) &&
480 memcmp(aptr, bptr, alen) == 0);
481}
482
484 bool copy;
485 bool force_precompute_hash;
486};
487
488static VALUE
489fstring_concurrent_set_create(VALUE str, void *data)
490{
491 struct fstr_create_arg *arg = data;
492
493 // Unless the string is empty or binary, its coderange has been precomputed.
494 int coderange = ENC_CODERANGE(str);
495
496 if (FL_TEST_RAW(str, STR_FAKESTR)) {
497 if (arg->copy) {
498 VALUE new_str;
499 long len = RSTRING_LEN(str);
500 long capa = len + sizeof(st_index_t);
501 int term_len = TERM_LEN(str);
502
503 if (arg->force_precompute_hash && STR_EMBEDDABLE_P(capa, term_len)) {
504 new_str = str_alloc_embed(rb_cString, capa + term_len);
505 memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str), len);
506 STR_SET_LEN(new_str, RSTRING_LEN(str));
507 TERM_FILL(RSTRING_END(new_str), TERM_LEN(str));
508 rb_enc_copy(new_str, str);
509 str_store_precomputed_hash(new_str, str_do_hash(str));
510 }
511 else {
512 new_str = str_new(rb_cString, RSTRING(str)->as.heap.ptr, RSTRING(str)->len);
513 rb_enc_copy(new_str, str);
514#ifdef PRECOMPUTED_FAKESTR_HASH
515 if (rb_str_capacity(new_str) >= RSTRING_LEN(str) + term_len + sizeof(st_index_t)) {
516 str_store_precomputed_hash(new_str, (st_index_t)RSTRING(str)->as.heap.aux.capa);
517 }
518#endif
519 }
520 str = new_str;
521 }
522 else {
523 str = str_new_static(rb_cString, RSTRING(str)->as.heap.ptr,
524 RSTRING(str)->len,
525 ENCODING_GET(str));
526 }
527 OBJ_FREEZE(str);
528 }
529 else {
530 if (!OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
531 str = str_new_frozen(rb_cString, str);
532 }
533 if (STR_SHARED_P(str)) { /* str should not be shared */
534 /* shared substring */
535 str_make_independent(str);
537 }
538 if (!BARE_STRING_P(str)) {
539 str = str_new_frozen(rb_cString, str);
540 }
541 }
542
543 ENC_CODERANGE_SET(str, coderange);
544 RBASIC(str)->flags |= RSTRING_FSTR;
545 if (!RB_OBJ_SHAREABLE_P(str)) {
546 RB_OBJ_SET_SHAREABLE(str);
547 }
548 RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
549 RUBY_ASSERT(RB_TYPE_P(str, T_STRING));
551 RUBY_ASSERT(!FL_TEST_RAW(str, STR_FAKESTR));
552 RUBY_ASSERT(!rb_shape_obj_has_ivars(str));
553 RUBY_ASSERT(RBASIC_CLASS(str) == rb_cString);
554 RUBY_ASSERT(!rb_objspace_garbage_object_p(str));
555
556 return str;
557}
558
559static const struct rb_concurrent_set_funcs fstring_concurrent_set_funcs = {
560 .hash = fstring_concurrent_set_hash,
561 .cmp = fstring_concurrent_set_cmp,
562 .create = fstring_concurrent_set_create,
563 .free = NULL,
564};
565
566void
567Init_fstring_table(void)
568{
569 fstring_table_obj = rb_concurrent_set_new(&fstring_concurrent_set_funcs, 8192);
570 rb_gc_register_address(&fstring_table_obj);
571}
572
573static VALUE
574register_fstring(VALUE str, bool copy, bool force_precompute_hash)
575{
576 struct fstr_create_arg args = {
577 .copy = copy,
578 .force_precompute_hash = force_precompute_hash
579 };
580
581#if SIZEOF_VOIDP == SIZEOF_LONG
582 if (FL_TEST_RAW(str, STR_FAKESTR)) {
583 // if the string hasn't been interned, we'll need the hash twice, so we
584 // compute it once and store it in capa
585 RSTRING(str)->as.heap.aux.capa = (long)str_do_hash(str);
586 }
587#endif
588
589 VALUE result = rb_concurrent_set_find_or_insert(&fstring_table_obj, str, &args);
590
591 RUBY_ASSERT(!rb_objspace_garbage_object_p(result));
592 RUBY_ASSERT(RB_TYPE_P(result, T_STRING));
593 RUBY_ASSERT(OBJ_FROZEN(result));
595 RUBY_ASSERT((rb_gc_verify_shareable(result), 1));
596 RUBY_ASSERT(!FL_TEST_RAW(result, STR_FAKESTR));
597 RUBY_ASSERT(RBASIC_CLASS(result) == rb_cString);
598
599 return result;
600}
601
602bool
603rb_obj_is_fstring_table(VALUE obj)
604{
605 ASSERT_vm_locking();
606
607 return obj == fstring_table_obj;
608}
609
610void
611rb_gc_free_fstring(VALUE obj)
612{
613 ASSERT_vm_locking_with_barrier();
614
615 RUBY_ASSERT(FL_TEST(obj, RSTRING_FSTR));
617 RUBY_ASSERT(!FL_TEST(obj, STR_SHARED));
618
619 rb_concurrent_set_delete_by_identity(fstring_table_obj, obj);
620
621 RB_DEBUG_COUNTER_INC(obj_str_fstr);
622
623 FL_UNSET(obj, RSTRING_FSTR);
624}
625
626void
627rb_fstring_foreach_with_replace(int (*callback)(VALUE *str, void *data), void *data)
628{
629 if (fstring_table_obj) {
630 rb_concurrent_set_foreach_with_replace(fstring_table_obj, callback, data);
631 }
632}
633
634static VALUE
635setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx)
636{
637 fake_str->basic.flags = T_STRING|RSTRING_NOEMBED|STR_NOFREE|STR_FAKESTR;
638 RBASIC_SET_SHAPE_ID((VALUE)fake_str, ROOT_SHAPE_ID);
639
640 if (!name) {
642 name = "";
643 }
644
645 ENCODING_SET_INLINED((VALUE)fake_str, encidx);
646
647 RBASIC_SET_CLASS_RAW((VALUE)fake_str, rb_cString);
648 fake_str->len = len;
649 fake_str->as.heap.ptr = (char *)name;
650 fake_str->as.heap.aux.capa = len;
651 return (VALUE)fake_str;
652}
653
654/*
655 * set up a fake string which refers a static string literal.
656 */
657VALUE
658rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc)
659{
660 return setup_fake_str(fake_str, name, len, rb_enc_to_index(enc));
661}
662
663/*
664 * rb_fstring_new and rb_fstring_cstr family create or lookup a frozen
665 * shared string which refers a static string literal. `ptr` must
666 * point a constant string.
667 */
668VALUE
669rb_fstring_new(const char *ptr, long len)
670{
671 struct RString fake_str = {RBASIC_INIT};
672 return register_fstring(setup_fake_str(&fake_str, ptr, len, ENCINDEX_US_ASCII), false, false);
673}
674
675VALUE
676rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc)
677{
678 struct RString fake_str = {RBASIC_INIT};
679 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), false, false);
680}
681
682VALUE
683rb_fstring_cstr(const char *ptr)
684{
685 return rb_fstring_new(ptr, strlen(ptr));
686}
687
688static inline bool
689single_byte_optimizable(VALUE str)
690{
691 int encindex = ENCODING_GET(str);
692 switch (encindex) {
693 case ENCINDEX_ASCII_8BIT:
694 case ENCINDEX_US_ASCII:
695 return true;
696 case ENCINDEX_UTF_8:
697 // For UTF-8 it's worth scanning the string coderange when unknown.
699 }
700 /* Conservative. It may be ENC_CODERANGE_UNKNOWN. */
701 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
702 return true;
703 }
704
705 if (rb_enc_mbmaxlen(rb_enc_from_index(encindex)) == 1) {
706 return true;
707 }
708
709 /* Conservative. Possibly single byte.
710 * "\xa1" in Shift_JIS for example. */
711 return false;
712}
713
715
716static inline const char *
717search_nonascii(const char *p, const char *e)
718{
719 const char *s, *t;
720
721#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
722# if SIZEOF_UINTPTR_T == 8
723# define NONASCII_MASK UINT64_C(0x8080808080808080)
724# elif SIZEOF_UINTPTR_T == 4
725# define NONASCII_MASK UINT32_C(0x80808080)
726# else
727# error "don't know what to do."
728# endif
729#else
730# if SIZEOF_UINTPTR_T == 8
731# define NONASCII_MASK ((uintptr_t)0x80808080UL << 32 | (uintptr_t)0x80808080UL)
732# elif SIZEOF_UINTPTR_T == 4
733# define NONASCII_MASK 0x80808080UL /* or...? */
734# else
735# error "don't know what to do."
736# endif
737#endif
738
739 if (UNALIGNED_WORD_ACCESS || e - p >= SIZEOF_VOIDP) {
740#if !UNALIGNED_WORD_ACCESS
741 if ((uintptr_t)p % SIZEOF_VOIDP) {
742 int l = SIZEOF_VOIDP - (uintptr_t)p % SIZEOF_VOIDP;
743 p += l;
744 switch (l) {
745 default: UNREACHABLE;
746#if SIZEOF_VOIDP > 4
747 case 7: if (p[-7]&0x80) return p-7;
748 case 6: if (p[-6]&0x80) return p-6;
749 case 5: if (p[-5]&0x80) return p-5;
750 case 4: if (p[-4]&0x80) return p-4;
751#endif
752 case 3: if (p[-3]&0x80) return p-3;
753 case 2: if (p[-2]&0x80) return p-2;
754 case 1: if (p[-1]&0x80) return p-1;
755 case 0: break;
756 }
757 }
758#endif
759#if defined(HAVE_BUILTIN___BUILTIN_ASSUME_ALIGNED) &&! UNALIGNED_WORD_ACCESS
760#define aligned_ptr(value) \
761 __builtin_assume_aligned((value), sizeof(uintptr_t))
762#else
763#define aligned_ptr(value) (value)
764#endif
765 s = aligned_ptr(p);
766 t = (e - (SIZEOF_VOIDP-1));
767#undef aligned_ptr
768 for (;s < t; s += sizeof(uintptr_t)) {
769 uintptr_t word;
770 memcpy(&word, s, sizeof(word));
771 if (word & NONASCII_MASK) {
772#ifdef WORDS_BIGENDIAN
773 return (const char *)s + (nlz_intptr(word&NONASCII_MASK)>>3);
774#else
775 return (const char *)s + (ntz_intptr(word&NONASCII_MASK)>>3);
776#endif
777 }
778 }
779 p = (const char *)s;
780 }
781
782 switch (e - p) {
783 default: UNREACHABLE;
784#if SIZEOF_VOIDP > 4
785 case 7: if (e[-7]&0x80) return e-7;
786 case 6: if (e[-6]&0x80) return e-6;
787 case 5: if (e[-5]&0x80) return e-5;
788 case 4: if (e[-4]&0x80) return e-4;
789#endif
790 case 3: if (e[-3]&0x80) return e-3;
791 case 2: if (e[-2]&0x80) return e-2;
792 case 1: if (e[-1]&0x80) return e-1;
793 case 0: return NULL;
794 }
795}
796
797static int
798coderange_scan(const char *p, long len, rb_encoding *enc)
799{
800 const char *e = p + len;
801
802 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
803 /* enc is ASCII-8BIT. ASCII-8BIT string never be broken. */
804 p = search_nonascii(p, e);
806 }
807
808 if (rb_enc_asciicompat(enc)) {
809 p = search_nonascii(p, e);
810 if (!p) return ENC_CODERANGE_7BIT;
811 for (;;) {
812 int ret = rb_enc_precise_mbclen(p, e, enc);
814 p += MBCLEN_CHARFOUND_LEN(ret);
815 if (p == e) break;
816 p = search_nonascii(p, e);
817 if (!p) break;
818 }
819 }
820 else {
821 while (p < e) {
822 int ret = rb_enc_precise_mbclen(p, e, enc);
824 p += MBCLEN_CHARFOUND_LEN(ret);
825 }
826 }
827 return ENC_CODERANGE_VALID;
828}
829
830long
831rb_str_coderange_scan_restartable(const char *s, const char *e, rb_encoding *enc, int *cr)
832{
833 const char *p = s;
834
835 if (*cr == ENC_CODERANGE_BROKEN)
836 return e - s;
837
838 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
839 /* enc is ASCII-8BIT. ASCII-8BIT string never be broken. */
840 if (*cr == ENC_CODERANGE_VALID) return e - s;
841 p = search_nonascii(p, e);
843 return e - s;
844 }
845 else if (rb_enc_asciicompat(enc)) {
846 p = search_nonascii(p, e);
847 if (!p) {
848 if (*cr != ENC_CODERANGE_VALID) *cr = ENC_CODERANGE_7BIT;
849 return e - s;
850 }
851 for (;;) {
852 int ret = rb_enc_precise_mbclen(p, e, enc);
853 if (!MBCLEN_CHARFOUND_P(ret)) {
855 return p - s;
856 }
857 p += MBCLEN_CHARFOUND_LEN(ret);
858 if (p == e) break;
859 p = search_nonascii(p, e);
860 if (!p) break;
861 }
862 }
863 else {
864 while (p < e) {
865 int ret = rb_enc_precise_mbclen(p, e, enc);
866 if (!MBCLEN_CHARFOUND_P(ret)) {
868 return p - s;
869 }
870 p += MBCLEN_CHARFOUND_LEN(ret);
871 }
872 }
874 return e - s;
875}
876
877static inline void
878str_enc_copy(VALUE str1, VALUE str2)
879{
880 rb_enc_set_index(str1, ENCODING_GET(str2));
881}
882
883/* Like str_enc_copy, but does not check frozen status of str1.
884 * You should use this only if you're certain that str1 is not frozen. */
885static inline void
886str_enc_copy_direct(VALUE str1, VALUE str2)
887{
888 int inlined_encoding = RB_ENCODING_GET_INLINED(str2);
889 if (inlined_encoding == ENCODING_INLINE_MAX) {
890 rb_enc_set_index(str1, rb_enc_get_index(str2));
891 }
892 else {
893 ENCODING_SET_INLINED(str1, inlined_encoding);
894 }
895}
896
897static void
898rb_enc_cr_str_copy_for_substr(VALUE dest, VALUE src)
899{
900 /* this function is designed for copying encoding and coderange
901 * from src to new string "dest" which is made from the part of src.
902 */
903 str_enc_copy(dest, src);
904 if (RSTRING_LEN(dest) == 0) {
905 if (!rb_enc_asciicompat(STR_ENC_GET(src)))
907 else
909 return;
910 }
911 switch (ENC_CODERANGE(src)) {
914 break;
916 if (!rb_enc_asciicompat(STR_ENC_GET(src)) ||
917 search_nonascii(RSTRING_PTR(dest), RSTRING_END(dest)))
919 else
921 break;
922 default:
923 break;
924 }
925}
926
927static void
928rb_enc_cr_str_exact_copy(VALUE dest, VALUE src)
929{
930 str_enc_copy(dest, src);
932}
933
934static int
935enc_coderange_scan(VALUE str, rb_encoding *enc)
936{
937 return coderange_scan(RSTRING_PTR(str), RSTRING_LEN(str), enc);
938}
939
940int
941rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc)
942{
943 return enc_coderange_scan(str, enc);
944}
945
946int
948{
949 int cr = ENC_CODERANGE(str);
950
951 if (cr == ENC_CODERANGE_UNKNOWN) {
952 cr = enc_coderange_scan(str, get_encoding(str));
953 ENC_CODERANGE_SET(str, cr);
954 }
955 return cr;
956}
957
958static inline bool
959rb_enc_str_asciicompat(VALUE str)
960{
961 int encindex = ENCODING_GET_INLINED(str);
962 return str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
963}
964
965int
967{
968 switch(ENC_CODERANGE(str)) {
970 return rb_enc_str_asciicompat(str) && is_ascii_string(str);
972 return true;
973 default:
974 return false;
975 }
976}
977
978static inline void
979str_mod_check(VALUE s, const char *p, long len)
980{
981 if (RSTRING_PTR(s) != p || RSTRING_LEN(s) != len){
982 rb_raise(rb_eRuntimeError, "string modified");
983 }
984}
985
986static size_t
987str_capacity(VALUE str, const int termlen)
988{
989 if (STR_EMBED_P(str)) {
990 return str_embed_capa(str) - termlen;
991 }
992 else if (FL_ANY_RAW(str, STR_SHARED|STR_NOFREE)) {
993 return RSTRING(str)->len;
994 }
995 else {
996 return RSTRING(str)->as.heap.aux.capa;
997 }
998}
999
1000size_t
1002{
1003 return str_capacity(str, TERM_LEN(str));
1004}
1005
1006static inline void
1007must_not_null(const char *ptr)
1008{
1009 if (!ptr) {
1010 rb_raise(rb_eArgError, "NULL pointer given");
1011 }
1012}
1013
1014static inline VALUE
1015str_alloc_embed(VALUE klass, size_t capa)
1016{
1017 size_t size = rb_str_embed_size(capa, 0);
1018 RUBY_ASSERT(size > 0);
1019 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
1020
1021 NEWOBJ_OF(str, struct RString, klass,
1023
1024 str->len = 0;
1025 str->as.embed.ary[0] = 0;
1026
1027 return (VALUE)str;
1028}
1029
1030static inline VALUE
1031str_alloc_heap(VALUE klass)
1032{
1033 NEWOBJ_OF(str, struct RString, klass,
1034 T_STRING | STR_NOEMBED | (RGENGC_WB_PROTECTED_STRING ? FL_WB_PROTECTED : 0), sizeof(struct RString), 0);
1035
1036 str->len = 0;
1037 str->as.heap.aux.capa = 0;
1038 str->as.heap.ptr = NULL;
1039
1040 return (VALUE)str;
1041}
1042
1043static inline VALUE
1044empty_str_alloc(VALUE klass)
1045{
1046 RUBY_DTRACE_CREATE_HOOK(STRING, 0);
1047 VALUE str = str_alloc_embed(klass, 0);
1048 memset(RSTRING(str)->as.embed.ary, 0, str_embed_capa(str));
1050 return str;
1051}
1052
1053static VALUE
1054str_enc_new(VALUE klass, const char *ptr, long len, rb_encoding *enc)
1055{
1056 VALUE str;
1057
1058 if (len < 0) {
1059 rb_raise(rb_eArgError, "negative string size (or size too big)");
1060 }
1061
1062 if (enc == NULL) {
1063 enc = rb_ascii8bit_encoding();
1064 }
1065
1066 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1067
1068 int termlen = rb_enc_mbminlen(enc);
1069
1070 if (STR_EMBEDDABLE_P(len, termlen)) {
1071 str = str_alloc_embed(klass, len + termlen);
1072 if (len == 0) {
1073 ENC_CODERANGE_SET(str, rb_enc_asciicompat(enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
1074 }
1075 }
1076 else {
1077 str = str_alloc_heap(klass);
1078 RSTRING(str)->as.heap.aux.capa = len;
1079 /* :FIXME: @shyouhei guesses `len + termlen` is guaranteed to never
1080 * integer overflow. If we can STATIC_ASSERT that, the following
1081 * mul_add_mul can be reverted to a simple ALLOC_N. */
1082 RSTRING(str)->as.heap.ptr =
1083 rb_xmalloc_mul_add_mul(sizeof(char), len, sizeof(char), termlen);
1084 }
1085
1086 rb_enc_raw_set(str, enc);
1087
1088 if (ptr) {
1089 memcpy(RSTRING_PTR(str), ptr, len);
1090 }
1091 else {
1092 memset(RSTRING_PTR(str), 0, len);
1093 }
1094
1095 STR_SET_LEN(str, len);
1096 TERM_FILL(RSTRING_PTR(str) + len, termlen);
1097 return str;
1098}
1099
1100static VALUE
1101str_new(VALUE klass, const char *ptr, long len)
1102{
1103 return str_enc_new(klass, ptr, len, rb_ascii8bit_encoding());
1104}
1105
1106VALUE
1107rb_str_new(const char *ptr, long len)
1108{
1109 return str_new(rb_cString, ptr, len);
1110}
1111
1112VALUE
1113rb_usascii_str_new(const char *ptr, long len)
1114{
1115 return str_enc_new(rb_cString, ptr, len, rb_usascii_encoding());
1116}
1117
1118VALUE
1119rb_utf8_str_new(const char *ptr, long len)
1120{
1121 return str_enc_new(rb_cString, ptr, len, rb_utf8_encoding());
1122}
1123
1124VALUE
1125rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
1126{
1127 return str_enc_new(rb_cString, ptr, len, enc);
1128}
1129
1130VALUE
1132{
1133 must_not_null(ptr);
1134 /* rb_str_new_cstr() can take pointer from non-malloc-generated
1135 * memory regions, and that cannot be detected by the MSAN. Just
1136 * trust the programmer that the argument passed here is a sane C
1137 * string. */
1138 __msan_unpoison_string(ptr);
1139 return rb_str_new(ptr, strlen(ptr));
1140}
1141
1142VALUE
1144{
1145 return rb_enc_str_new_cstr(ptr, rb_usascii_encoding());
1146}
1147
1148VALUE
1150{
1151 return rb_enc_str_new_cstr(ptr, rb_utf8_encoding());
1152}
1153
1154VALUE
1155rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc)
1156{
1157 must_not_null(ptr);
1158 if (rb_enc_mbminlen(enc) != 1) {
1159 rb_raise(rb_eArgError, "wchar encoding given");
1160 }
1161 return rb_enc_str_new(ptr, strlen(ptr), enc);
1162}
1163
1164static VALUE
1165str_new_static(VALUE klass, const char *ptr, long len, int encindex)
1166{
1167 VALUE str;
1168
1169 if (len < 0) {
1170 rb_raise(rb_eArgError, "negative string size (or size too big)");
1171 }
1172
1173 if (!ptr) {
1174 str = str_enc_new(klass, ptr, len, rb_enc_from_index(encindex));
1175 }
1176 else {
1177 RUBY_DTRACE_CREATE_HOOK(STRING, len);
1178 str = str_alloc_heap(klass);
1179 RSTRING(str)->len = len;
1180 RSTRING(str)->as.heap.ptr = (char *)ptr;
1181 RSTRING(str)->as.heap.aux.capa = len;
1182 RBASIC(str)->flags |= STR_NOFREE;
1183 rb_enc_associate_index(str, encindex);
1184 }
1185 return str;
1186}
1187
1188VALUE
1189rb_str_new_static(const char *ptr, long len)
1190{
1191 return str_new_static(rb_cString, ptr, len, 0);
1192}
1193
1194VALUE
1196{
1197 return str_new_static(rb_cString, ptr, len, ENCINDEX_US_ASCII);
1198}
1199
1200VALUE
1202{
1203 return str_new_static(rb_cString, ptr, len, ENCINDEX_UTF_8);
1204}
1205
1206VALUE
1207rb_enc_str_new_static(const char *ptr, long len, rb_encoding *enc)
1208{
1209 return str_new_static(rb_cString, ptr, len, rb_enc_to_index(enc));
1210}
1211
1212static VALUE str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len,
1213 rb_encoding *from, rb_encoding *to,
1214 int ecflags, VALUE ecopts);
1215
1216static inline bool
1217is_enc_ascii_string(VALUE str, rb_encoding *enc)
1218{
1219 int encidx = rb_enc_to_index(enc);
1220 if (rb_enc_get_index(str) == encidx)
1221 return is_ascii_string(str);
1222 return enc_coderange_scan(str, enc) == ENC_CODERANGE_7BIT;
1223}
1224
1225VALUE
1226rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
1227{
1228 long len;
1229 const char *ptr;
1230 VALUE newstr;
1231
1232 if (!to) return str;
1233 if (!from) from = rb_enc_get(str);
1234 if (from == to) return str;
1235 if ((rb_enc_asciicompat(to) && is_enc_ascii_string(str, from)) ||
1236 rb_is_ascii8bit_enc(to)) {
1237 if (STR_ENC_GET(str) != to) {
1238 str = rb_str_dup(str);
1239 rb_enc_associate(str, to);
1240 }
1241 return str;
1242 }
1243
1244 RSTRING_GETMEM(str, ptr, len);
1245 newstr = str_cat_conv_enc_opts(rb_str_buf_new(len), 0, ptr, len,
1246 from, to, ecflags, ecopts);
1247 if (NIL_P(newstr)) {
1248 /* some error, return original */
1249 return str;
1250 }
1251 return newstr;
1252}
1253
1254VALUE
1255rb_str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len,
1256 rb_encoding *from, int ecflags, VALUE ecopts)
1257{
1258 long olen;
1259
1260 olen = RSTRING_LEN(newstr);
1261 if (ofs < -olen || olen < ofs)
1262 rb_raise(rb_eIndexError, "index %ld out of string", ofs);
1263 if (ofs < 0) ofs += olen;
1264 if (!from) {
1265 STR_SET_LEN(newstr, ofs);
1266 return rb_str_cat(newstr, ptr, len);
1267 }
1268
1269 rb_str_modify(newstr);
1270 return str_cat_conv_enc_opts(newstr, ofs, ptr, len, from,
1271 rb_enc_get(newstr),
1272 ecflags, ecopts);
1273}
1274
1275VALUE
1276rb_str_initialize(VALUE str, const char *ptr, long len, rb_encoding *enc)
1277{
1278 STR_SET_LEN(str, 0);
1279 rb_enc_associate(str, enc);
1280 rb_str_cat(str, ptr, len);
1281 return str;
1282}
1283
1284static VALUE
1285str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len,
1286 rb_encoding *from, rb_encoding *to,
1287 int ecflags, VALUE ecopts)
1288{
1289 rb_econv_t *ec;
1291 long olen;
1292 VALUE econv_wrapper;
1293 const unsigned char *start, *sp;
1294 unsigned char *dest, *dp;
1295 size_t converted_output = (size_t)ofs;
1296
1297 olen = rb_str_capacity(newstr);
1298
1299 econv_wrapper = rb_obj_alloc(rb_cEncodingConverter);
1300 RBASIC_CLEAR_CLASS(econv_wrapper);
1301 ec = rb_econv_open_opts(from->name, to->name, ecflags, ecopts);
1302 if (!ec) return Qnil;
1303 DATA_PTR(econv_wrapper) = ec;
1304
1305 sp = (unsigned char*)ptr;
1306 start = sp;
1307 while ((dest = (unsigned char*)RSTRING_PTR(newstr)),
1308 (dp = dest + converted_output),
1309 (ret = rb_econv_convert(ec, &sp, start + len, &dp, dest + olen, 0)),
1311 /* destination buffer short */
1312 size_t converted_input = sp - start;
1313 size_t rest = len - converted_input;
1314 converted_output = dp - dest;
1315 rb_str_set_len(newstr, converted_output);
1316 if (converted_input && converted_output &&
1317 rest < (LONG_MAX / converted_output)) {
1318 rest = (rest * converted_output) / converted_input;
1319 }
1320 else {
1321 rest = olen;
1322 }
1323 olen += rest < 2 ? 2 : rest;
1324 rb_str_resize(newstr, olen);
1325 }
1326 DATA_PTR(econv_wrapper) = 0;
1327 RB_GC_GUARD(econv_wrapper);
1328 rb_econv_close(ec);
1329 switch (ret) {
1330 case econv_finished:
1331 len = dp - (unsigned char*)RSTRING_PTR(newstr);
1332 rb_str_set_len(newstr, len);
1333 rb_enc_associate(newstr, to);
1334 return newstr;
1335
1336 default:
1337 return Qnil;
1338 }
1339}
1340
1341VALUE
1342rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
1343{
1344 return rb_str_conv_enc_opts(str, from, to, 0, Qnil);
1345}
1346
1347VALUE
1348rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *eenc)
1349{
1350 rb_encoding *ienc;
1351 VALUE str;
1352 const int eidx = rb_enc_to_index(eenc);
1353
1354 if (!ptr) {
1355 return rb_enc_str_new(ptr, len, eenc);
1356 }
1357
1358 /* ASCII-8BIT case, no conversion */
1359 if ((eidx == rb_ascii8bit_encindex()) ||
1360 (eidx == rb_usascii_encindex() && search_nonascii(ptr, ptr + len))) {
1361 return rb_str_new(ptr, len);
1362 }
1363 /* no default_internal or same encoding, no conversion */
1364 ienc = rb_default_internal_encoding();
1365 if (!ienc || eenc == ienc) {
1366 return rb_enc_str_new(ptr, len, eenc);
1367 }
1368 /* ASCII compatible, and ASCII only string, no conversion in
1369 * default_internal */
1370 if ((eidx == rb_ascii8bit_encindex()) ||
1371 (eidx == rb_usascii_encindex()) ||
1372 (rb_enc_asciicompat(eenc) && !search_nonascii(ptr, ptr + len))) {
1373 return rb_enc_str_new(ptr, len, ienc);
1374 }
1375 /* convert from the given encoding to default_internal */
1376 str = rb_enc_str_new(NULL, 0, ienc);
1377 /* when the conversion failed for some reason, just ignore the
1378 * default_internal and result in the given encoding as-is. */
1379 if (NIL_P(rb_str_cat_conv_enc_opts(str, 0, ptr, len, eenc, 0, Qnil))) {
1380 rb_str_initialize(str, ptr, len, eenc);
1381 }
1382 return str;
1383}
1384
1385VALUE
1386rb_external_str_with_enc(VALUE str, rb_encoding *eenc)
1387{
1388 int eidx = rb_enc_to_index(eenc);
1389 if (eidx == rb_usascii_encindex() &&
1390 !is_ascii_string(str)) {
1391 rb_enc_associate_index(str, rb_ascii8bit_encindex());
1392 return str;
1393 }
1394 rb_enc_associate_index(str, eidx);
1395 return rb_str_conv_enc(str, eenc, rb_default_internal_encoding());
1396}
1397
1398VALUE
1399rb_external_str_new(const char *ptr, long len)
1400{
1401 return rb_external_str_new_with_enc(ptr, len, rb_default_external_encoding());
1402}
1403
1404VALUE
1406{
1407 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_default_external_encoding());
1408}
1409
1410VALUE
1411rb_locale_str_new(const char *ptr, long len)
1412{
1413 return rb_external_str_new_with_enc(ptr, len, rb_locale_encoding());
1414}
1415
1416VALUE
1418{
1419 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_locale_encoding());
1420}
1421
1422VALUE
1424{
1425 return rb_external_str_new_with_enc(ptr, len, rb_filesystem_encoding());
1426}
1427
1428VALUE
1430{
1431 return rb_external_str_new_with_enc(ptr, strlen(ptr), rb_filesystem_encoding());
1432}
1433
1434VALUE
1436{
1437 return rb_str_export_to_enc(str, rb_default_external_encoding());
1438}
1439
1440VALUE
1442{
1443 return rb_str_export_to_enc(str, rb_locale_encoding());
1444}
1445
1446VALUE
1447rb_str_export_to_enc(VALUE str, rb_encoding *enc)
1448{
1449 return rb_str_conv_enc(str, STR_ENC_GET(str), enc);
1450}
1451
1452static VALUE
1453str_replace_shared_without_enc(VALUE str2, VALUE str)
1454{
1455 const int termlen = TERM_LEN(str);
1456 char *ptr;
1457 long len;
1458
1459 RSTRING_GETMEM(str, ptr, len);
1460 if (str_embed_capa(str2) >= len + termlen) {
1461 char *ptr2 = RSTRING(str2)->as.embed.ary;
1462 STR_SET_EMBED(str2);
1463 memcpy(ptr2, RSTRING_PTR(str), len);
1464 TERM_FILL(ptr2+len, termlen);
1465 }
1466 else {
1467 VALUE root;
1468 if (STR_SHARED_P(str)) {
1469 root = RSTRING(str)->as.heap.aux.shared;
1470 RSTRING_GETMEM(str, ptr, len);
1471 }
1472 else {
1473 root = rb_str_new_frozen(str);
1474 RSTRING_GETMEM(root, ptr, len);
1475 }
1476 RUBY_ASSERT(OBJ_FROZEN(root));
1477
1478 if (!STR_EMBED_P(str2) && !FL_TEST_RAW(str2, STR_SHARED|STR_NOFREE)) {
1479 if (FL_TEST_RAW(str2, STR_SHARED_ROOT)) {
1480 rb_fatal("about to free a possible shared root");
1481 }
1482 char *ptr2 = STR_HEAP_PTR(str2);
1483 if (ptr2 != ptr) {
1484 ruby_sized_xfree(ptr2, STR_HEAP_SIZE(str2));
1485 }
1486 }
1487 FL_SET(str2, STR_NOEMBED);
1488 RSTRING(str2)->as.heap.ptr = ptr;
1489 STR_SET_SHARED(str2, root);
1490 }
1491
1492 STR_SET_LEN(str2, len);
1493
1494 return str2;
1495}
1496
1497static VALUE
1498str_replace_shared(VALUE str2, VALUE str)
1499{
1500 str_replace_shared_without_enc(str2, str);
1501 rb_enc_cr_str_exact_copy(str2, str);
1502 return str2;
1503}
1504
1505static VALUE
1506str_new_shared(VALUE klass, VALUE str)
1507{
1508 return str_replace_shared(str_alloc_heap(klass), str);
1509}
1510
1511VALUE
1513{
1514 return str_new_shared(rb_obj_class(str), str);
1515}
1516
1517VALUE
1519{
1520 if (RB_FL_TEST_RAW(orig, FL_FREEZE | STR_CHILLED) == FL_FREEZE) return orig;
1521 return str_new_frozen(rb_obj_class(orig), orig);
1522}
1523
1524static VALUE
1525rb_str_new_frozen_String(VALUE orig)
1526{
1527 if (OBJ_FROZEN(orig) && rb_obj_class(orig) == rb_cString) return orig;
1528 return str_new_frozen(rb_cString, orig);
1529}
1530
1531
1532VALUE
1533rb_str_frozen_bare_string(VALUE orig)
1534{
1535 if (RB_LIKELY(BARE_STRING_P(orig) && OBJ_FROZEN_RAW(orig))) return orig;
1536 return str_new_frozen(rb_cString, orig);
1537}
1538
1539VALUE
1540rb_str_tmp_frozen_acquire(VALUE orig)
1541{
1542 if (OBJ_FROZEN_RAW(orig)) return orig;
1543 return str_new_frozen_buffer(0, orig, FALSE);
1544}
1545
1546VALUE
1547rb_str_tmp_frozen_no_embed_acquire(VALUE orig)
1548{
1549 if (OBJ_FROZEN_RAW(orig) && !STR_EMBED_P(orig) && !rb_str_reembeddable_p(orig)) return orig;
1550 if (STR_SHARED_P(orig) && !STR_EMBED_P(RSTRING(orig)->as.heap.aux.shared)) return rb_str_tmp_frozen_acquire(orig);
1551
1552 VALUE str = str_alloc_heap(0);
1553 OBJ_FREEZE(str);
1554 /* Always set the STR_SHARED_ROOT to ensure it does not get re-embedded. */
1555 FL_SET(str, STR_SHARED_ROOT);
1556
1557 size_t capa = str_capacity(orig, TERM_LEN(orig));
1558
1559 /* If the string is embedded then we want to create a copy that is heap
1560 * allocated. If the string is shared then the shared root must be
1561 * embedded, so we want to create a copy. If the string is a shared root
1562 * then it must be embedded, so we want to create a copy. */
1563 if (STR_EMBED_P(orig) || FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT | RSTRING_FSTR)) {
1564 RSTRING(str)->as.heap.ptr = rb_xmalloc_mul_add_mul(sizeof(char), capa, sizeof(char), TERM_LEN(orig));
1565 memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), capa);
1566 }
1567 else {
1568 /* orig must be heap allocated and not shared, so we can safely transfer
1569 * the pointer to str. */
1570 RSTRING(str)->as.heap.ptr = RSTRING(orig)->as.heap.ptr;
1571 RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1572 RBASIC(orig)->flags &= ~STR_NOFREE;
1573 STR_SET_SHARED(orig, str);
1574 if (RB_OBJ_SHAREABLE_P(orig)) {
1575 RB_OBJ_SET_SHAREABLE(str);
1576 RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
1577 }
1578 }
1579
1580 RSTRING(str)->len = RSTRING(orig)->len;
1581 RSTRING(str)->as.heap.aux.capa = capa;
1582
1583 return str;
1584}
1585
1586void
1587rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
1588{
1589 if (RBASIC_CLASS(tmp) != 0)
1590 return;
1591
1592 if (STR_EMBED_P(tmp)) {
1594 }
1595 else if (FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_SHARED &&
1596 !OBJ_FROZEN_RAW(orig)) {
1597 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1598
1599 if (shared == tmp && !FL_TEST_RAW(tmp, STR_BORROWED)) {
1600 RUBY_ASSERT(RSTRING(orig)->as.heap.ptr == RSTRING(tmp)->as.heap.ptr);
1601 RUBY_ASSERT(RSTRING_LEN(orig) == RSTRING_LEN(tmp));
1602
1603 /* Unshare orig since the root (tmp) only has this one child. */
1604 FL_UNSET_RAW(orig, STR_SHARED);
1605 RSTRING(orig)->as.heap.aux.capa = RSTRING(tmp)->as.heap.aux.capa;
1606 RBASIC(orig)->flags |= RBASIC(tmp)->flags & STR_NOFREE;
1608
1609 /* Make tmp embedded and empty so it is safe for sweeping. */
1610 STR_SET_EMBED(tmp);
1611 STR_SET_LEN(tmp, 0);
1612 }
1613 }
1614}
1615
1616static VALUE
1617str_new_frozen(VALUE klass, VALUE orig)
1618{
1619 return str_new_frozen_buffer(klass, orig, TRUE);
1620}
1621
1622static VALUE
1623heap_str_make_shared(VALUE klass, VALUE orig)
1624{
1625 RUBY_ASSERT(!STR_EMBED_P(orig));
1626 RUBY_ASSERT(!STR_SHARED_P(orig));
1628
1629 VALUE str = str_alloc_heap(klass);
1630 STR_SET_LEN(str, RSTRING_LEN(orig));
1631 RSTRING(str)->as.heap.ptr = RSTRING_PTR(orig);
1632 RSTRING(str)->as.heap.aux.capa = RSTRING(orig)->as.heap.aux.capa;
1633 RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1634 RBASIC(orig)->flags &= ~STR_NOFREE;
1635 STR_SET_SHARED(orig, str);
1636 if (klass == 0)
1637 FL_UNSET_RAW(str, STR_BORROWED);
1638 return str;
1639}
1640
1641static VALUE
1642str_new_frozen_buffer(VALUE klass, VALUE orig, int copy_encoding)
1643{
1644 VALUE str;
1645
1646 long len = RSTRING_LEN(orig);
1647 rb_encoding *enc = copy_encoding ? STR_ENC_GET(orig) : rb_ascii8bit_encoding();
1648 int termlen = copy_encoding ? TERM_LEN(orig) : 1;
1649
1650 if (STR_EMBED_P(orig) || STR_EMBEDDABLE_P(len, termlen)) {
1651 str = str_enc_new(klass, RSTRING_PTR(orig), len, enc);
1652 RUBY_ASSERT(STR_EMBED_P(str));
1653 }
1654 else {
1655 if (FL_TEST_RAW(orig, STR_SHARED)) {
1656 VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1657 long ofs = RSTRING(orig)->as.heap.ptr - RSTRING_PTR(shared);
1658 long rest = RSTRING_LEN(shared) - ofs - RSTRING_LEN(orig);
1659 RUBY_ASSERT(ofs >= 0);
1660 RUBY_ASSERT(rest >= 0);
1661 RUBY_ASSERT(ofs + rest <= RSTRING_LEN(shared));
1662 RUBY_ASSERT(OBJ_FROZEN(shared));
1663
1664 if ((ofs > 0) || (rest > 0) ||
1665 (klass != RBASIC(shared)->klass) ||
1666 ENCODING_GET(shared) != ENCODING_GET(orig)) {
1667 str = str_new_shared(klass, shared);
1668 RUBY_ASSERT(!STR_EMBED_P(str));
1669 RSTRING(str)->as.heap.ptr += ofs;
1670 STR_SET_LEN(str, RSTRING_LEN(str) - (ofs + rest));
1671 }
1672 else {
1673 if (RBASIC_CLASS(shared) == 0)
1674 FL_SET_RAW(shared, STR_BORROWED);
1675 return shared;
1676 }
1677 }
1678 else if (STR_EMBEDDABLE_P(RSTRING_LEN(orig), TERM_LEN(orig))) {
1679 str = str_alloc_embed(klass, RSTRING_LEN(orig) + TERM_LEN(orig));
1680 STR_SET_EMBED(str);
1681 memcpy(RSTRING_PTR(str), RSTRING_PTR(orig), RSTRING_LEN(orig));
1682 STR_SET_LEN(str, RSTRING_LEN(orig));
1683 ENC_CODERANGE_SET(str, ENC_CODERANGE(orig));
1684 TERM_FILL(RSTRING_END(str), TERM_LEN(orig));
1685 }
1686 else {
1687 if (RB_OBJ_SHAREABLE_P(orig)) {
1688 str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
1689 }
1690 else {
1691 str = heap_str_make_shared(klass, orig);
1692 }
1693 }
1694 }
1695
1696 if (copy_encoding) rb_enc_cr_str_exact_copy(str, orig);
1697 OBJ_FREEZE(str);
1698 return str;
1699}
1700
1701VALUE
1702rb_str_new_with_class(VALUE obj, const char *ptr, long len)
1703{
1704 return str_enc_new(rb_obj_class(obj), ptr, len, STR_ENC_GET(obj));
1705}
1706
1707static VALUE
1708str_new_empty_String(VALUE str)
1709{
1710 VALUE v = rb_str_new(0, 0);
1711 rb_enc_copy(v, str);
1712 return v;
1713}
1714
1715#define STR_BUF_MIN_SIZE 63
1716
1717VALUE
1719{
1720 if (STR_EMBEDDABLE_P(capa, 1)) {
1721 return str_alloc_embed(rb_cString, capa + 1);
1722 }
1723
1724 VALUE str = str_alloc_heap(rb_cString);
1725
1726 RSTRING(str)->as.heap.aux.capa = capa;
1727 RSTRING(str)->as.heap.ptr = ALLOC_N(char, (size_t)capa + 1);
1728 RSTRING(str)->as.heap.ptr[0] = '\0';
1729
1730 return str;
1731}
1732
1733VALUE
1735{
1736 VALUE str;
1737 long len = strlen(ptr);
1738
1739 str = rb_str_buf_new(len);
1740 rb_str_buf_cat(str, ptr, len);
1741
1742 return str;
1743}
1744
1745VALUE
1747{
1748 return str_new(0, 0, len);
1749}
1750
1751void
1753{
1754 if (STR_EMBED_P(str)) {
1755 RB_DEBUG_COUNTER_INC(obj_str_embed);
1756 }
1757 else if (FL_TEST(str, STR_SHARED | STR_NOFREE)) {
1758 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_SHARED));
1759 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared, FL_TEST(str, STR_NOFREE));
1760 }
1761 else {
1762 RB_DEBUG_COUNTER_INC(obj_str_ptr);
1763 ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
1764 }
1765}
1766
1767size_t
1768rb_str_memsize(VALUE str)
1769{
1770 if (FL_TEST(str, STR_NOEMBED|STR_SHARED|STR_NOFREE) == STR_NOEMBED) {
1771 return STR_HEAP_SIZE(str);
1772 }
1773 else {
1774 return 0;
1775 }
1776}
1777
1778VALUE
1780{
1781 return rb_convert_type_with_id(str, T_STRING, "String", idTo_str);
1782}
1783
1784static inline void str_discard(VALUE str);
1785static void str_shared_replace(VALUE str, VALUE str2);
1786
1787void
1789{
1790 if (str != str2) str_shared_replace(str, str2);
1791}
1792
1793static void
1794str_shared_replace(VALUE str, VALUE str2)
1795{
1796 rb_encoding *enc;
1797 int cr;
1798 int termlen;
1799
1800 RUBY_ASSERT(str2 != str);
1801 enc = STR_ENC_GET(str2);
1802 cr = ENC_CODERANGE(str2);
1803 str_discard(str);
1804 termlen = rb_enc_mbminlen(enc);
1805
1806 STR_SET_LEN(str, RSTRING_LEN(str2));
1807
1808 if (str_embed_capa(str) >= RSTRING_LEN(str2) + termlen) {
1809 STR_SET_EMBED(str);
1810 memcpy(RSTRING_PTR(str), RSTRING_PTR(str2), (size_t)RSTRING_LEN(str2) + termlen);
1811 }
1812 else {
1813 if (STR_EMBED_P(str2)) {
1814 RUBY_ASSERT(!FL_TEST(str2, STR_SHARED));
1815 long len = RSTRING_LEN(str2);
1816 RUBY_ASSERT(len + termlen <= str_embed_capa(str2));
1817
1818 char *new_ptr = ALLOC_N(char, len + termlen);
1819 memcpy(new_ptr, RSTRING(str2)->as.embed.ary, len + termlen);
1820 RSTRING(str2)->as.heap.ptr = new_ptr;
1821 STR_SET_LEN(str2, len);
1822 RSTRING(str2)->as.heap.aux.capa = len;
1823 STR_SET_NOEMBED(str2);
1824 }
1825
1826 STR_SET_NOEMBED(str);
1827 FL_UNSET(str, STR_SHARED);
1828 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1829
1830 if (FL_TEST(str2, STR_SHARED)) {
1831 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1832 STR_SET_SHARED(str, shared);
1833 }
1834 else {
1835 RSTRING(str)->as.heap.aux.capa = RSTRING(str2)->as.heap.aux.capa;
1836 }
1837
1838 /* abandon str2 */
1839 STR_SET_EMBED(str2);
1840 RSTRING_PTR(str2)[0] = 0;
1841 STR_SET_LEN(str2, 0);
1842 }
1843
1844 // We used str2's termlen above so we set enc raw
1845 // to avoid adjusting it based on str1's old enc.
1846 rb_enc_raw_set(str, enc);
1847 ENC_CODERANGE_SET(str, cr);
1848}
1849
1850VALUE
1852{
1853 VALUE str;
1854
1855 if (RB_TYPE_P(obj, T_STRING)) {
1856 return obj;
1857 }
1858 str = rb_funcall(obj, idTo_s, 0);
1859 return rb_obj_as_string_result(str, obj);
1860}
1861
1862VALUE
1863rb_obj_as_string_result(VALUE str, VALUE obj)
1864{
1865 if (!RB_TYPE_P(str, T_STRING))
1866 return rb_any_to_s(obj);
1867 return str;
1868}
1869
1870static VALUE
1871str_replace(VALUE str, VALUE str2)
1872{
1873 long len;
1874
1875 len = RSTRING_LEN(str2);
1876 if (STR_SHARED_P(str2)) {
1877 VALUE shared = RSTRING(str2)->as.heap.aux.shared;
1878 RUBY_ASSERT(OBJ_FROZEN(shared));
1879 STR_SET_NOEMBED(str);
1880 STR_SET_LEN(str, len);
1881 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1882 STR_SET_SHARED(str, shared);
1883 rb_enc_cr_str_exact_copy(str, str2);
1884 }
1885 else {
1886 str_replace_shared(str, str2);
1887 }
1888
1889 return str;
1890}
1891
1892static inline VALUE
1893ec_str_alloc_embed(struct rb_execution_context_struct *ec, VALUE klass, size_t capa)
1894{
1895 size_t size = rb_str_embed_size(capa, 0);
1896 RUBY_ASSERT(size > 0);
1897 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
1898
1899 NEWOBJ_OF(str, struct RString, klass,
1901
1902 str->len = 0;
1903
1904 return (VALUE)str;
1905}
1906
1907static inline VALUE
1908ec_str_alloc_heap(struct rb_execution_context_struct *ec, VALUE klass)
1909{
1910 NEWOBJ_OF(str, struct RString, klass,
1911 T_STRING | STR_NOEMBED | (RGENGC_WB_PROTECTED_STRING ? FL_WB_PROTECTED : 0), sizeof(struct RString), ec);
1912
1913 str->as.heap.aux.capa = 0;
1914 str->as.heap.ptr = NULL;
1915
1916 return (VALUE)str;
1917}
1918
1919static inline VALUE
1920str_duplicate_setup_encoding(VALUE str, VALUE dup, VALUE flags)
1921{
1922 int encidx = 0;
1923 if ((flags & ENCODING_MASK) == (ENCODING_INLINE_MAX<<ENCODING_SHIFT)) {
1924 encidx = rb_enc_get_index(str);
1925 flags &= ~ENCODING_MASK;
1926 }
1927 FL_SET_RAW(dup, flags & ~FL_FREEZE);
1928 if (encidx) rb_enc_associate_index(dup, encidx);
1929 return dup;
1930}
1931
1932static const VALUE flag_mask = ENC_CODERANGE_MASK | ENCODING_MASK | FL_FREEZE;
1933
1934static inline VALUE
1935str_duplicate_setup_embed(VALUE klass, VALUE str, VALUE dup)
1936{
1937 VALUE flags = FL_TEST_RAW(str, flag_mask);
1938 long len = RSTRING_LEN(str);
1939
1940 RUBY_ASSERT(STR_EMBED_P(dup));
1941 RUBY_ASSERT(str_embed_capa(dup) >= len + TERM_LEN(str));
1942 MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + TERM_LEN(str));
1943 STR_SET_LEN(dup, RSTRING_LEN(str));
1944 return str_duplicate_setup_encoding(str, dup, flags);
1945}
1946
1947static inline VALUE
1948str_duplicate_setup_heap(VALUE klass, VALUE str, VALUE dup)
1949{
1950 VALUE flags = FL_TEST_RAW(str, flag_mask);
1951 VALUE root = str;
1952 if (FL_TEST_RAW(str, STR_SHARED)) {
1953 root = RSTRING(str)->as.heap.aux.shared;
1954 }
1955 else if (UNLIKELY(!OBJ_FROZEN_RAW(str))) {
1956 root = str = str_new_frozen(klass, str);
1957 flags = FL_TEST_RAW(str, flag_mask);
1958 }
1959 RUBY_ASSERT(!STR_SHARED_P(root));
1960 RUBY_ASSERT(RB_OBJ_FROZEN_RAW(root));
1961
1962 RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
1963 FL_SET(root, STR_SHARED_ROOT);
1964 RB_OBJ_WRITE(dup, &RSTRING(dup)->as.heap.aux.shared, root);
1965 flags |= RSTRING_NOEMBED | STR_SHARED;
1966
1967 STR_SET_LEN(dup, RSTRING_LEN(str));
1968 return str_duplicate_setup_encoding(str, dup, flags);
1969}
1970
1971static inline VALUE
1972str_duplicate_setup(VALUE klass, VALUE str, VALUE dup)
1973{
1974 if (STR_EMBED_P(str)) {
1975 return str_duplicate_setup_embed(klass, str, dup);
1976 }
1977 else {
1978 return str_duplicate_setup_heap(klass, str, dup);
1979 }
1980}
1981
1982static inline VALUE
1983str_duplicate(VALUE klass, VALUE str)
1984{
1985 VALUE dup;
1986 if (STR_EMBED_P(str)) {
1987 dup = str_alloc_embed(klass, RSTRING_LEN(str) + TERM_LEN(str));
1988 }
1989 else {
1990 dup = str_alloc_heap(klass);
1991 }
1992
1993 return str_duplicate_setup(klass, str, dup);
1994}
1995
1996VALUE
1998{
1999 return str_duplicate(rb_obj_class(str), str);
2000}
2001
2002/* :nodoc: */
2003VALUE
2004rb_str_dup_m(VALUE str)
2005{
2006 if (LIKELY(BARE_STRING_P(str))) {
2007 return str_duplicate(rb_cString, str);
2008 }
2009 else {
2010 return rb_obj_dup(str);
2011 }
2012}
2013
2014VALUE
2016{
2017 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2018 return str_duplicate(rb_cString, str);
2019}
2020
2021VALUE
2022rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled)
2023{
2024 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2025 VALUE new_str, klass = rb_cString;
2026
2027 if (!(chilled && RTEST(rb_ivar_defined(str, id_debug_created_info))) && STR_EMBED_P(str)) {
2028 new_str = ec_str_alloc_embed(ec, klass, RSTRING_LEN(str) + TERM_LEN(str));
2029 str_duplicate_setup_embed(klass, str, new_str);
2030 }
2031 else {
2032 new_str = ec_str_alloc_heap(ec, klass);
2033 str_duplicate_setup_heap(klass, str, new_str);
2034 }
2035 if (chilled) {
2036 FL_SET_RAW(new_str, STR_CHILLED_LITERAL);
2037 }
2038 return new_str;
2039}
2040
2041VALUE
2042rb_str_with_debug_created_info(VALUE str, VALUE path, int line)
2043{
2044 VALUE debug_info = rb_ary_new_from_args(2, path, INT2FIX(line));
2045 if (OBJ_FROZEN_RAW(str)) str = rb_str_dup(str);
2046 rb_ivar_set(str, id_debug_created_info, rb_ary_freeze(debug_info));
2047 FL_SET_RAW(str, STR_CHILLED_LITERAL);
2048 return rb_str_freeze(str);
2049}
2050
2051/*
2052 * The documentation block below uses an include (instead of inline text)
2053 * because the included text has non-ASCII characters (which are not allowed in a C file).
2054 */
2055
2056/*
2057 *
2058 * call-seq:
2059 * String.new(string = ''.encode(Encoding::ASCII_8BIT) , **options) -> new_string
2060 *
2061 * :include: doc/string/new.rdoc
2062 *
2063 */
2064
2065static VALUE
2066rb_str_init(int argc, VALUE *argv, VALUE str)
2067{
2068 static ID keyword_ids[2];
2069 VALUE orig, opt, venc, vcapa;
2070 VALUE kwargs[2];
2071 rb_encoding *enc = 0;
2072 int n;
2073
2074 if (!keyword_ids[0]) {
2075 keyword_ids[0] = rb_id_encoding();
2076 CONST_ID(keyword_ids[1], "capacity");
2077 }
2078
2079 n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2080 if (!NIL_P(opt)) {
2081 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2082 venc = kwargs[0];
2083 vcapa = kwargs[1];
2084 if (!UNDEF_P(venc) && !NIL_P(venc)) {
2085 enc = rb_to_encoding(venc);
2086 }
2087 if (!UNDEF_P(vcapa) && !NIL_P(vcapa)) {
2088 long capa = NUM2LONG(vcapa);
2089 long len = 0;
2090 int termlen = enc ? rb_enc_mbminlen(enc) : 1;
2091
2092 if (capa < STR_BUF_MIN_SIZE) {
2093 capa = STR_BUF_MIN_SIZE;
2094 }
2095 if (n == 1) {
2096 StringValue(orig);
2097 len = RSTRING_LEN(orig);
2098 if (capa < len) {
2099 capa = len;
2100 }
2101 if (orig == str) n = 0;
2102 }
2103 str_modifiable(str);
2104 if (STR_EMBED_P(str) || FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2105 /* make noembed always */
2106 const size_t size = (size_t)capa + termlen;
2107 const char *const old_ptr = RSTRING_PTR(str);
2108 const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
2109 char *new_ptr = ALLOC_N(char, size);
2110 if (STR_EMBED_P(str)) RUBY_ASSERT((long)osize <= str_embed_capa(str));
2111 memcpy(new_ptr, old_ptr, osize < size ? osize : size);
2112 FL_UNSET_RAW(str, STR_SHARED|STR_NOFREE);
2113 RSTRING(str)->as.heap.ptr = new_ptr;
2114 }
2115 else if (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
2116 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
2117 (size_t)capa + termlen, STR_HEAP_SIZE(str));
2118 }
2119 STR_SET_LEN(str, len);
2120 TERM_FILL(&RSTRING(str)->as.heap.ptr[len], termlen);
2121 if (n == 1) {
2122 memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), len);
2123 rb_enc_cr_str_exact_copy(str, orig);
2124 }
2125 FL_SET(str, STR_NOEMBED);
2126 RSTRING(str)->as.heap.aux.capa = capa;
2127 }
2128 else if (n == 1) {
2129 rb_str_replace(str, orig);
2130 }
2131 if (enc) {
2132 rb_enc_associate(str, enc);
2134 }
2135 }
2136 else if (n == 1) {
2137 rb_str_replace(str, orig);
2138 }
2139 return str;
2140}
2141
2142/* :nodoc: */
2143static VALUE
2144rb_str_s_new(int argc, VALUE *argv, VALUE klass)
2145{
2146 if (klass != rb_cString) {
2147 return rb_class_new_instance_pass_kw(argc, argv, klass);
2148 }
2149
2150 static ID keyword_ids[2];
2151 VALUE orig, opt, encoding = Qnil, capacity = Qnil;
2152 VALUE kwargs[2];
2153 rb_encoding *enc = NULL;
2154
2155 int n = rb_scan_args(argc, argv, "01:", &orig, &opt);
2156 if (NIL_P(opt)) {
2157 return rb_class_new_instance_pass_kw(argc, argv, klass);
2158 }
2159
2160 keyword_ids[0] = rb_id_encoding();
2161 CONST_ID(keyword_ids[1], "capacity");
2162 rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2163 encoding = kwargs[0];
2164 capacity = kwargs[1];
2165
2166 if (n == 1) {
2167 orig = StringValue(orig);
2168 }
2169 else {
2170 orig = Qnil;
2171 }
2172
2173 if (UNDEF_P(encoding)) {
2174 if (!NIL_P(orig)) {
2175 encoding = rb_obj_encoding(orig);
2176 }
2177 }
2178
2179 if (!UNDEF_P(encoding)) {
2180 enc = rb_to_encoding(encoding);
2181 }
2182
2183 // If capacity is nil, we're basically just duping `orig`.
2184 if (UNDEF_P(capacity)) {
2185 if (NIL_P(orig)) {
2186 VALUE empty_str = str_new(klass, "", 0);
2187 if (enc) {
2188 rb_enc_associate(empty_str, enc);
2189 }
2190 return empty_str;
2191 }
2192 VALUE copy = str_duplicate(klass, orig);
2193 rb_enc_associate(copy, enc);
2194 ENC_CODERANGE_CLEAR(copy);
2195 return copy;
2196 }
2197
2198 long capa = 0;
2199 capa = NUM2LONG(capacity);
2200 if (capa < 0) {
2201 capa = 0;
2202 }
2203
2204 if (!NIL_P(orig)) {
2205 long orig_capa = rb_str_capacity(orig);
2206 if (orig_capa > capa) {
2207 capa = orig_capa;
2208 }
2209 }
2210
2211 VALUE str = str_enc_new(klass, NULL, capa, enc);
2212 STR_SET_LEN(str, 0);
2213 TERM_FILL(RSTRING_PTR(str), enc ? rb_enc_mbmaxlen(enc) : 1);
2214
2215 if (!NIL_P(orig)) {
2216 rb_str_buf_append(str, orig);
2217 }
2218
2219 return str;
2220}
2221
2222#ifdef NONASCII_MASK
2223#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2224
2225/*
2226 * UTF-8 leading bytes have either 0xxxxxxx or 11xxxxxx
2227 * bit representation. (see https://en.wikipedia.org/wiki/UTF-8)
2228 * Therefore, the following pseudocode can detect UTF-8 leading bytes.
2229 *
2230 * if (!(byte & 0x80))
2231 * byte |= 0x40; // turn on bit6
2232 * return ((byte>>6) & 1); // bit6 represent whether this byte is leading or not.
2233 *
2234 * This function calculates whether a byte is leading or not for all bytes
2235 * in the argument word by concurrently using the above logic, and then
2236 * adds up the number of leading bytes in the word.
2237 */
2238static inline uintptr_t
2239count_utf8_lead_bytes_with_word(const uintptr_t *s)
2240{
2241 uintptr_t d = *s;
2242
2243 /* Transform so that bit0 indicates whether we have a UTF-8 leading byte or not. */
2244 d = (d>>6) | (~d>>7);
2245 d &= NONASCII_MASK >> 7;
2246
2247 /* Gather all bytes. */
2248#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2249 /* use only if it can use POPCNT */
2250 return rb_popcount_intptr(d);
2251#else
2252 d += (d>>8);
2253 d += (d>>16);
2254# if SIZEOF_VOIDP == 8
2255 d += (d>>32);
2256# endif
2257 return (d&0xF);
2258#endif
2259}
2260#endif
2261
2262static inline long
2263enc_strlen(const char *p, const char *e, rb_encoding *enc, int cr)
2264{
2265 long c;
2266 const char *q;
2267
2268 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2269 long diff = (long)(e - p);
2270 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2271 }
2272#ifdef NONASCII_MASK
2273 else if (cr == ENC_CODERANGE_VALID && enc == rb_utf8_encoding()) {
2274 uintptr_t len = 0;
2275 if ((int)sizeof(uintptr_t) * 2 < e - p) {
2276 const uintptr_t *s, *t;
2277 const uintptr_t lowbits = sizeof(uintptr_t) - 1;
2278 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2279 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
2280 while (p < (const char *)s) {
2281 if (is_utf8_lead_byte(*p)) len++;
2282 p++;
2283 }
2284 while (s < t) {
2285 len += count_utf8_lead_bytes_with_word(s);
2286 s++;
2287 }
2288 p = (const char *)s;
2289 }
2290 while (p < e) {
2291 if (is_utf8_lead_byte(*p)) len++;
2292 p++;
2293 }
2294 return (long)len;
2295 }
2296#endif
2297 else if (rb_enc_asciicompat(enc)) {
2298 c = 0;
2299 if (ENC_CODERANGE_CLEAN_P(cr)) {
2300 while (p < e) {
2301 if (ISASCII(*p)) {
2302 q = search_nonascii(p, e);
2303 if (!q)
2304 return c + (e - p);
2305 c += q - p;
2306 p = q;
2307 }
2308 p += rb_enc_fast_mbclen(p, e, enc);
2309 c++;
2310 }
2311 }
2312 else {
2313 while (p < e) {
2314 if (ISASCII(*p)) {
2315 q = search_nonascii(p, e);
2316 if (!q)
2317 return c + (e - p);
2318 c += q - p;
2319 p = q;
2320 }
2321 p += rb_enc_mbclen(p, e, enc);
2322 c++;
2323 }
2324 }
2325 return c;
2326 }
2327
2328 for (c=0; p<e; c++) {
2329 p += rb_enc_mbclen(p, e, enc);
2330 }
2331 return c;
2332}
2333
2334long
2335rb_enc_strlen(const char *p, const char *e, rb_encoding *enc)
2336{
2337 return enc_strlen(p, e, enc, ENC_CODERANGE_UNKNOWN);
2338}
2339
2340/* To get strlen with cr
2341 * Note that given cr is not used.
2342 */
2343long
2344rb_enc_strlen_cr(const char *p, const char *e, rb_encoding *enc, int *cr)
2345{
2346 long c;
2347 const char *q;
2348 int ret;
2349
2350 *cr = 0;
2351 if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2352 long diff = (long)(e - p);
2353 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2354 }
2355 else if (rb_enc_asciicompat(enc)) {
2356 c = 0;
2357 while (p < e) {
2358 if (ISASCII(*p)) {
2359 q = search_nonascii(p, e);
2360 if (!q) {
2361 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2362 return c + (e - p);
2363 }
2364 c += q - p;
2365 p = q;
2366 }
2367 ret = rb_enc_precise_mbclen(p, e, enc);
2368 if (MBCLEN_CHARFOUND_P(ret)) {
2369 *cr |= ENC_CODERANGE_VALID;
2370 p += MBCLEN_CHARFOUND_LEN(ret);
2371 }
2372 else {
2374 p++;
2375 }
2376 c++;
2377 }
2378 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2379 return c;
2380 }
2381
2382 for (c=0; p<e; c++) {
2383 ret = rb_enc_precise_mbclen(p, e, enc);
2384 if (MBCLEN_CHARFOUND_P(ret)) {
2385 *cr |= ENC_CODERANGE_VALID;
2386 p += MBCLEN_CHARFOUND_LEN(ret);
2387 }
2388 else {
2390 if (p + rb_enc_mbminlen(enc) <= e)
2391 p += rb_enc_mbminlen(enc);
2392 else
2393 p = e;
2394 }
2395 }
2396 if (!*cr) *cr = ENC_CODERANGE_7BIT;
2397 return c;
2398}
2399
2400/* enc must be str's enc or rb_enc_check(str, str2) */
2401static long
2402str_strlen(VALUE str, rb_encoding *enc)
2403{
2404 const char *p, *e;
2405 int cr;
2406
2407 if (single_byte_optimizable(str)) return RSTRING_LEN(str);
2408 if (!enc) enc = STR_ENC_GET(str);
2409 p = RSTRING_PTR(str);
2410 e = RSTRING_END(str);
2411 cr = ENC_CODERANGE(str);
2412
2413 if (cr == ENC_CODERANGE_UNKNOWN) {
2414 long n = rb_enc_strlen_cr(p, e, enc, &cr);
2415 if (cr) ENC_CODERANGE_SET(str, cr);
2416 return n;
2417 }
2418 else {
2419 return enc_strlen(p, e, enc, cr);
2420 }
2421}
2422
2423long
2425{
2426 return str_strlen(str, NULL);
2427}
2428
2429/*
2430 * call-seq:
2431 * length -> integer
2432 *
2433 * :include: doc/string/length.rdoc
2434 *
2435 */
2436
2437VALUE
2439{
2440 return LONG2NUM(str_strlen(str, NULL));
2441}
2442
2443/*
2444 * call-seq:
2445 * bytesize -> integer
2446 *
2447 * :include: doc/string/bytesize.rdoc
2448 *
2449 */
2450
2451VALUE
2452rb_str_bytesize(VALUE str)
2453{
2454 return LONG2NUM(RSTRING_LEN(str));
2455}
2456
2457/*
2458 * call-seq:
2459 * empty? -> true or false
2460 *
2461 * Returns whether the length of +self+ is zero:
2462 *
2463 * 'hello'.empty? # => false
2464 * ' '.empty? # => false
2465 * ''.empty? # => true
2466 *
2467 * Related: see {Querying}[rdoc-ref:String@Querying].
2468 */
2469
2470static VALUE
2471rb_str_empty(VALUE str)
2472{
2473 return RBOOL(RSTRING_LEN(str) == 0);
2474}
2475
2476/*
2477 * call-seq:
2478 * self + other_string -> new_string
2479 *
2480 * Returns a new string containing +other_string+ concatenated to +self+:
2481 *
2482 * 'Hello from ' + self.to_s # => "Hello from main"
2483 *
2484 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2485 */
2486
2487VALUE
2489{
2490 VALUE str3;
2491 rb_encoding *enc;
2492 char *ptr1, *ptr2, *ptr3;
2493 long len1, len2;
2494 int termlen;
2495
2496 StringValue(str2);
2497 enc = rb_enc_check_str(str1, str2);
2498 RSTRING_GETMEM(str1, ptr1, len1);
2499 RSTRING_GETMEM(str2, ptr2, len2);
2500 termlen = rb_enc_mbminlen(enc);
2501 if (len1 > LONG_MAX - len2) {
2502 rb_raise(rb_eArgError, "string size too big");
2503 }
2504 str3 = str_enc_new(rb_cString, 0, len1+len2, enc);
2505 ptr3 = RSTRING_PTR(str3);
2506 memcpy(ptr3, ptr1, len1);
2507 memcpy(ptr3+len1, ptr2, len2);
2508 TERM_FILL(&ptr3[len1+len2], termlen);
2509
2510 ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
2512 RB_GC_GUARD(str1);
2513 RB_GC_GUARD(str2);
2514 return str3;
2515}
2516
2517/* A variant of rb_str_plus that does not raise but return Qundef instead. */
2518VALUE
2519rb_str_opt_plus(VALUE str1, VALUE str2)
2520{
2521 RUBY_ASSERT(RBASIC_CLASS(str1) == rb_cString);
2522 RUBY_ASSERT(RBASIC_CLASS(str2) == rb_cString);
2523 long len1, len2;
2524 MAYBE_UNUSED(char) *ptr1, *ptr2;
2525 RSTRING_GETMEM(str1, ptr1, len1);
2526 RSTRING_GETMEM(str2, ptr2, len2);
2527 int enc1 = rb_enc_get_index(str1);
2528 int enc2 = rb_enc_get_index(str2);
2529
2530 if (enc1 < 0) {
2531 return Qundef;
2532 }
2533 else if (enc2 < 0) {
2534 return Qundef;
2535 }
2536 else if (enc1 != enc2) {
2537 return Qundef;
2538 }
2539 else if (len1 > LONG_MAX - len2) {
2540 return Qundef;
2541 }
2542 else {
2543 return rb_str_plus(str1, str2);
2544 }
2545
2546}
2547
2548/*
2549 * call-seq:
2550 * self * n -> new_string
2551 *
2552 * Returns a new string containing +n+ copies of +self+:
2553 *
2554 * 'Ho!' * 3 # => "Ho!Ho!Ho!"
2555 * 'No!' * 0 # => ""
2556 *
2557 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2558 */
2559
2560VALUE
2562{
2563 VALUE str2;
2564 long n, len;
2565 char *ptr2;
2566 int termlen;
2567
2568 if (times == INT2FIX(1)) {
2569 return str_duplicate(rb_cString, str);
2570 }
2571 if (times == INT2FIX(0)) {
2572 str2 = str_alloc_embed(rb_cString, 0);
2573 rb_enc_copy(str2, str);
2574 return str2;
2575 }
2576 len = NUM2LONG(times);
2577 if (len < 0) {
2578 rb_raise(rb_eArgError, "negative argument");
2579 }
2580 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2581 if (STR_EMBEDDABLE_P(len, 1)) {
2582 str2 = str_alloc_embed(rb_cString, len + 1);
2583 memset(RSTRING_PTR(str2), 0, len + 1);
2584 }
2585 else {
2586 str2 = str_alloc_heap(rb_cString);
2587 RSTRING(str2)->as.heap.aux.capa = len;
2588 RSTRING(str2)->as.heap.ptr = ZALLOC_N(char, (size_t)len + 1);
2589 }
2590 STR_SET_LEN(str2, len);
2591 rb_enc_copy(str2, str);
2592 return str2;
2593 }
2594 if (len && LONG_MAX/len < RSTRING_LEN(str)) {
2595 rb_raise(rb_eArgError, "argument too big");
2596 }
2597
2598 len *= RSTRING_LEN(str);
2599 termlen = TERM_LEN(str);
2600 str2 = str_enc_new(rb_cString, 0, len, STR_ENC_GET(str));
2601 ptr2 = RSTRING_PTR(str2);
2602 if (len) {
2603 n = RSTRING_LEN(str);
2604 memcpy(ptr2, RSTRING_PTR(str), n);
2605 while (n <= len/2) {
2606 memcpy(ptr2 + n, ptr2, n);
2607 n *= 2;
2608 }
2609 memcpy(ptr2 + n, ptr2, len-n);
2610 }
2611 STR_SET_LEN(str2, len);
2612 TERM_FILL(&ptr2[len], termlen);
2613 rb_enc_cr_str_copy_for_substr(str2, str);
2614
2615 return str2;
2616}
2617
2618/*
2619 * call-seq:
2620 * self % object -> new_string
2621 *
2622 * Returns the result of formatting +object+ into the format specifications
2623 * contained in +self+
2624 * (see {Format Specifications}[rdoc-ref:language/format_specifications.rdoc]):
2625 *
2626 * '%05d' % 123 # => "00123"
2627 *
2628 * If +self+ contains multiple format specifications,
2629 * +object+ must be an array or hash containing the objects to be formatted:
2630 *
2631 * '%-5s: %016x' % [ 'ID', self.object_id ] # => "ID : 00002b054ec93168"
2632 * 'foo = %{foo}' % {foo: 'bar'} # => "foo = bar"
2633 * 'foo = %{foo}, baz = %{baz}' % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
2634 *
2635 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
2636 */
2637
2638static VALUE
2639rb_str_format_m(VALUE str, VALUE arg)
2640{
2641 VALUE tmp = rb_check_array_type(arg);
2642
2643 if (!NIL_P(tmp)) {
2644 VALUE result = rb_str_format(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str);
2645 RB_GC_GUARD(tmp);
2646 return result;
2647 }
2648 return rb_str_format(1, &arg, str);
2649}
2650
2651static inline void
2652rb_check_lockedtmp(VALUE str)
2653{
2654 if (FL_TEST(str, STR_TMPLOCK)) {
2655 rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked");
2656 }
2657}
2658
2659// If none of these flags are set, we know we have an modifiable string.
2660// If any is set, we need to do more detailed checks.
2661#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2662static inline void
2663str_modifiable(VALUE str)
2664{
2665 RUBY_ASSERT(ruby_thread_has_gvl_p());
2666
2667 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2668 if (CHILLED_STRING_P(str)) {
2669 CHILLED_STRING_MUTATED(str);
2670 }
2671 rb_check_lockedtmp(str);
2672 rb_check_frozen(str);
2673 }
2674}
2675
2676static inline int
2677str_dependent_p(VALUE str)
2678{
2679 if (STR_EMBED_P(str) || !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2680 return FALSE;
2681 }
2682 else {
2683 return TRUE;
2684 }
2685}
2686
2687// If none of these flags are set, we know we have an independent string.
2688// If any is set, we need to do more detailed checks.
2689#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2690static inline int
2691str_independent(VALUE str)
2692{
2693 RUBY_ASSERT(ruby_thread_has_gvl_p());
2694
2695 if (RB_UNLIKELY(FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2696 str_modifiable(str);
2697 return !str_dependent_p(str);
2698 }
2699 return TRUE;
2700}
2701
2702static void
2703str_make_independent_expand(VALUE str, long len, long expand, const int termlen)
2704{
2705 RUBY_ASSERT(ruby_thread_has_gvl_p());
2706
2707 char *ptr;
2708 char *oldptr;
2709 long capa = len + expand;
2710
2711 if (len > capa) len = capa;
2712
2713 if (!STR_EMBED_P(str) && str_embed_capa(str) >= capa + termlen) {
2714 ptr = RSTRING(str)->as.heap.ptr;
2715 STR_SET_EMBED(str);
2716 memcpy(RSTRING(str)->as.embed.ary, ptr, len);
2717 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
2718 STR_SET_LEN(str, len);
2719 return;
2720 }
2721
2722 ptr = ALLOC_N(char, (size_t)capa + termlen);
2723 oldptr = RSTRING_PTR(str);
2724 if (oldptr) {
2725 memcpy(ptr, oldptr, len);
2726 }
2727 if (FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2728 xfree(oldptr);
2729 }
2730 STR_SET_NOEMBED(str);
2731 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2732 TERM_FILL(ptr + len, termlen);
2733 RSTRING(str)->as.heap.ptr = ptr;
2734 STR_SET_LEN(str, len);
2735 RSTRING(str)->as.heap.aux.capa = capa;
2736}
2737
2738void
2739rb_str_modify(VALUE str)
2740{
2741 if (!str_independent(str))
2742 str_make_independent(str);
2744}
2745
2746void
2748{
2749 RUBY_ASSERT(ruby_thread_has_gvl_p());
2750
2751 int termlen = TERM_LEN(str);
2752 long len = RSTRING_LEN(str);
2753
2754 if (expand < 0) {
2755 rb_raise(rb_eArgError, "negative expanding string size");
2756 }
2757 if (expand >= LONG_MAX - len) {
2758 rb_raise(rb_eArgError, "string size too big");
2759 }
2760
2761 if (!str_independent(str)) {
2762 str_make_independent_expand(str, len, expand, termlen);
2763 }
2764 else if (expand > 0) {
2765 RESIZE_CAPA_TERM(str, len + expand, termlen);
2766 }
2768}
2769
2770/* As rb_str_modify(), but don't clear coderange */
2771static void
2772str_modify_keep_cr(VALUE str)
2773{
2774 if (!str_independent(str))
2775 str_make_independent(str);
2777 /* Force re-scan later */
2779}
2780
2781static inline void
2782str_discard(VALUE str)
2783{
2784 str_modifiable(str);
2785 if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2786 ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2787 RSTRING(str)->as.heap.ptr = 0;
2788 STR_SET_LEN(str, 0);
2789 }
2790}
2791
2792void
2794{
2795 int encindex = rb_enc_get_index(str);
2796
2797 if (RB_UNLIKELY(encindex == -1)) {
2798 rb_raise(rb_eTypeError, "not encoding capable object");
2799 }
2800
2801 if (RB_LIKELY(str_encindex_fastpath(encindex))) {
2802 return;
2803 }
2804
2805 rb_encoding *enc = rb_enc_from_index(encindex);
2806 if (!rb_enc_asciicompat(enc)) {
2807 rb_raise(rb_eEncCompatError, "ASCII incompatible encoding: %s", rb_enc_name(enc));
2808 }
2809}
2810
2811VALUE
2813{
2814 RUBY_ASSERT(ruby_thread_has_gvl_p());
2815
2816 VALUE s = *ptr;
2817 if (!RB_TYPE_P(s, T_STRING)) {
2818 s = rb_str_to_str(s);
2819 *ptr = s;
2820 }
2821 return s;
2822}
2823
2824char *
2826{
2827 VALUE str = rb_string_value(ptr);
2828 return RSTRING_PTR(str);
2829}
2830
2831static int
2832zero_filled(const char *s, int n)
2833{
2834 for (; n > 0; --n) {
2835 if (*s++) return 0;
2836 }
2837 return 1;
2838}
2839
2840static const char *
2841str_null_char(const char *s, long len, const int minlen, rb_encoding *enc)
2842{
2843 const char *e = s + len;
2844
2845 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2846 if (zero_filled(s, minlen)) return s;
2847 }
2848 return 0;
2849}
2850
2851static char *
2852str_fill_term(VALUE str, char *s, long len, int termlen)
2853{
2854 /* This function assumes that (capa + termlen) bytes of memory
2855 * is allocated, like many other functions in this file.
2856 */
2857 if (str_dependent_p(str)) {
2858 if (!zero_filled(s + len, termlen))
2859 str_make_independent_expand(str, len, 0L, termlen);
2860 }
2861 else {
2862 TERM_FILL(s + len, termlen);
2863 return s;
2864 }
2865 return RSTRING_PTR(str);
2866}
2867
2868void
2869rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen)
2870{
2871 long capa = str_capacity(str, oldtermlen) + oldtermlen;
2872 long len = RSTRING_LEN(str);
2873
2874 RUBY_ASSERT(capa >= len);
2875 if (capa - len < termlen) {
2876 rb_check_lockedtmp(str);
2877 str_make_independent_expand(str, len, 0L, termlen);
2878 }
2879 else if (str_dependent_p(str)) {
2880 if (termlen > oldtermlen)
2881 str_make_independent_expand(str, len, 0L, termlen);
2882 }
2883 else {
2884 if (!STR_EMBED_P(str)) {
2885 /* modify capa instead of realloc */
2886 RUBY_ASSERT(!FL_TEST((str), STR_SHARED));
2887 RSTRING(str)->as.heap.aux.capa = capa - termlen;
2888 }
2889 if (termlen > oldtermlen) {
2890 TERM_FILL(RSTRING_PTR(str) + len, termlen);
2891 }
2892 }
2893
2894 return;
2895}
2896
2897static char *
2898str_null_check(VALUE str, int *w)
2899{
2900 char *s = RSTRING_PTR(str);
2901 long len = RSTRING_LEN(str);
2902 rb_encoding *enc = rb_enc_get(str);
2903 const int minlen = rb_enc_mbminlen(enc);
2904
2905 if (minlen > 1) {
2906 *w = 1;
2907 if (str_null_char(s, len, minlen, enc)) {
2908 return NULL;
2909 }
2910 return str_fill_term(str, s, len, minlen);
2911 }
2912 *w = 0;
2913 if (!s || memchr(s, 0, len)) {
2914 return NULL;
2915 }
2916 if (s[len]) {
2917 s = str_fill_term(str, s, len, minlen);
2918 }
2919 return s;
2920}
2921
2922char *
2923rb_str_to_cstr(VALUE str)
2924{
2925 int w;
2926 return str_null_check(str, &w);
2927}
2928
2929char *
2931{
2932 VALUE str = rb_string_value(ptr);
2933 int w;
2934 char *s = str_null_check(str, &w);
2935 if (!s) {
2936 if (w) {
2937 rb_raise(rb_eArgError, "string contains null char");
2938 }
2939 rb_raise(rb_eArgError, "string contains null byte");
2940 }
2941 return s;
2942}
2943
2944char *
2945rb_str_fill_terminator(VALUE str, const int newminlen)
2946{
2947 char *s = RSTRING_PTR(str);
2948 long len = RSTRING_LEN(str);
2949 return str_fill_term(str, s, len, newminlen);
2950}
2951
2952VALUE
2954{
2955 str = rb_check_convert_type_with_id(str, T_STRING, "String", idTo_str);
2956 return str;
2957}
2958
2959/*
2960 * call-seq:
2961 * String.try_convert(object) -> object, new_string, or nil
2962 *
2963 * Attempts to convert the given +object+ to a string.
2964 *
2965 * If +object+ is already a string, returns +object+, unmodified.
2966 *
2967 * Otherwise if +object+ responds to <tt>:to_str</tt>,
2968 * calls <tt>object.to_str</tt> and returns the result.
2969 *
2970 * Returns +nil+ if +object+ does not respond to <tt>:to_str</tt>.
2971 *
2972 * Raises an exception unless <tt>object.to_str</tt> returns a string.
2973 */
2974static VALUE
2975rb_str_s_try_convert(VALUE dummy, VALUE str)
2976{
2977 return rb_check_string_type(str);
2978}
2979
2980static char*
2981str_nth_len(const char *p, const char *e, long *nthp, rb_encoding *enc)
2982{
2983 long nth = *nthp;
2984 if (rb_enc_mbmaxlen(enc) == 1) {
2985 p += nth;
2986 }
2987 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
2988 p += nth * rb_enc_mbmaxlen(enc);
2989 }
2990 else if (rb_enc_asciicompat(enc)) {
2991 const char *p2, *e2;
2992 int n;
2993
2994 while (p < e && 0 < nth) {
2995 e2 = p + nth;
2996 if (e < e2) {
2997 *nthp = nth;
2998 return (char *)e;
2999 }
3000 if (ISASCII(*p)) {
3001 p2 = search_nonascii(p, e2);
3002 if (!p2) {
3003 nth -= e2 - p;
3004 *nthp = nth;
3005 return (char *)e2;
3006 }
3007 nth -= p2 - p;
3008 p = p2;
3009 }
3010 n = rb_enc_mbclen(p, e, enc);
3011 p += n;
3012 nth--;
3013 }
3014 *nthp = nth;
3015 if (nth != 0) {
3016 return (char *)e;
3017 }
3018 return (char *)p;
3019 }
3020 else {
3021 while (p < e && nth--) {
3022 p += rb_enc_mbclen(p, e, enc);
3023 }
3024 }
3025 if (p > e) p = e;
3026 *nthp = nth;
3027 return (char*)p;
3028}
3029
3030char*
3031rb_enc_nth(const char *p, const char *e, long nth, rb_encoding *enc)
3032{
3033 return str_nth_len(p, e, &nth, enc);
3034}
3035
3036static char*
3037str_nth(const char *p, const char *e, long nth, rb_encoding *enc, int singlebyte)
3038{
3039 if (singlebyte)
3040 p += nth;
3041 else {
3042 p = str_nth_len(p, e, &nth, enc);
3043 }
3044 if (!p) return 0;
3045 if (p > e) p = e;
3046 return (char *)p;
3047}
3048
3049/* char offset to byte offset */
3050static long
3051str_offset(const char *p, const char *e, long nth, rb_encoding *enc, int singlebyte)
3052{
3053 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3054 if (!pp) return e - p;
3055 return pp - p;
3056}
3057
3058long
3059rb_str_offset(VALUE str, long pos)
3060{
3061 return str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
3062 STR_ENC_GET(str), single_byte_optimizable(str));
3063}
3064
3065#ifdef NONASCII_MASK
3066static char *
3067str_utf8_nth(const char *p, const char *e, long *nthp)
3068{
3069 long nth = *nthp;
3070 if ((int)SIZEOF_VOIDP * 2 < e - p && (int)SIZEOF_VOIDP * 2 < nth) {
3071 const uintptr_t *s, *t;
3072 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3073 s = (const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3074 t = (const uintptr_t*)(~lowbits & (uintptr_t)e);
3075 while (p < (const char *)s) {
3076 if (is_utf8_lead_byte(*p)) nth--;
3077 p++;
3078 }
3079 do {
3080 nth -= count_utf8_lead_bytes_with_word(s);
3081 s++;
3082 } while (s < t && (int)SIZEOF_VOIDP <= nth);
3083 p = (char *)s;
3084 }
3085 while (p < e) {
3086 if (is_utf8_lead_byte(*p)) {
3087 if (nth == 0) break;
3088 nth--;
3089 }
3090 p++;
3091 }
3092 *nthp = nth;
3093 return (char *)p;
3094}
3095
3096static long
3097str_utf8_offset(const char *p, const char *e, long nth)
3098{
3099 const char *pp = str_utf8_nth(p, e, &nth);
3100 return pp - p;
3101}
3102#endif
3103
3104/* byte offset to char offset */
3105long
3106rb_str_sublen(VALUE str, long pos)
3107{
3108 if (single_byte_optimizable(str) || pos < 0)
3109 return pos;
3110 else {
3111 char *p = RSTRING_PTR(str);
3112 return enc_strlen(p, p + pos, STR_ENC_GET(str), ENC_CODERANGE(str));
3113 }
3114}
3115
3116static VALUE
3117str_subseq(VALUE str, long beg, long len)
3118{
3119 VALUE str2;
3120
3121 RUBY_ASSERT(beg >= 0);
3122 RUBY_ASSERT(len >= 0);
3123 RUBY_ASSERT(beg+len <= RSTRING_LEN(str));
3124
3125 const int termlen = TERM_LEN(str);
3126 if (!SHARABLE_SUBSTRING_P(beg, len, RSTRING_LEN(str))) {
3127 str2 = rb_str_new(RSTRING_PTR(str) + beg, len);
3128 RB_GC_GUARD(str);
3129 return str2;
3130 }
3131
3132 str2 = str_alloc_heap(rb_cString);
3133 if (str_embed_capa(str2) >= len + termlen) {
3134 char *ptr2 = RSTRING(str2)->as.embed.ary;
3135 STR_SET_EMBED(str2);
3136 memcpy(ptr2, RSTRING_PTR(str) + beg, len);
3137 TERM_FILL(ptr2+len, termlen);
3138
3139 STR_SET_LEN(str2, len);
3140 RB_GC_GUARD(str);
3141 }
3142 else {
3143 str_replace_shared(str2, str);
3144 RUBY_ASSERT(!STR_EMBED_P(str2));
3145 ENC_CODERANGE_CLEAR(str2);
3146 RSTRING(str2)->as.heap.ptr += beg;
3147 if (RSTRING_LEN(str2) > len) {
3148 STR_SET_LEN(str2, len);
3149 }
3150 }
3151
3152 return str2;
3153}
3154
3155VALUE
3156rb_str_subseq(VALUE str, long beg, long len)
3157{
3158 VALUE str2 = str_subseq(str, beg, len);
3159 rb_enc_cr_str_copy_for_substr(str2, str);
3160 return str2;
3161}
3162
3163char *
3164rb_str_subpos(VALUE str, long beg, long *lenp)
3165{
3166 long len = *lenp;
3167 long slen = -1L;
3168 const long blen = RSTRING_LEN(str);
3169 rb_encoding *enc = STR_ENC_GET(str);
3170 char *p, *s = RSTRING_PTR(str), *e = s + blen;
3171
3172 if (len < 0) return 0;
3173 if (beg < 0 && -beg < 0) return 0;
3174 if (!blen) {
3175 len = 0;
3176 }
3177 if (single_byte_optimizable(str)) {
3178 if (beg > blen) return 0;
3179 if (beg < 0) {
3180 beg += blen;
3181 if (beg < 0) return 0;
3182 }
3183 if (len > blen - beg)
3184 len = blen - beg;
3185 if (len < 0) return 0;
3186 p = s + beg;
3187 goto end;
3188 }
3189 if (beg < 0) {
3190 if (len > -beg) len = -beg;
3191 if ((ENC_CODERANGE(str) == ENC_CODERANGE_VALID) &&
3192 (-beg * rb_enc_mbmaxlen(enc) < blen / 8)) {
3193 beg = -beg;
3194 while (beg-- > len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3195 p = e;
3196 if (!p) return 0;
3197 while (len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3198 if (!p) return 0;
3199 len = e - p;
3200 goto end;
3201 }
3202 else {
3203 slen = str_strlen(str, enc);
3204 beg += slen;
3205 if (beg < 0) return 0;
3206 p = s + beg;
3207 if (len == 0) goto end;
3208 }
3209 }
3210 else if (beg > 0 && beg > blen) {
3211 return 0;
3212 }
3213 if (len == 0) {
3214 if (beg > str_strlen(str, enc)) return 0; /* str's enc */
3215 p = s + beg;
3216 }
3217#ifdef NONASCII_MASK
3218 else if (ENC_CODERANGE(str) == ENC_CODERANGE_VALID &&
3219 enc == rb_utf8_encoding()) {
3220 p = str_utf8_nth(s, e, &beg);
3221 if (beg > 0) return 0;
3222 len = str_utf8_offset(p, e, len);
3223 }
3224#endif
3225 else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) {
3226 int char_sz = rb_enc_mbmaxlen(enc);
3227
3228 p = s + beg * char_sz;
3229 if (p > e) {
3230 return 0;
3231 }
3232 else if (len * char_sz > e - p)
3233 len = e - p;
3234 else
3235 len *= char_sz;
3236 }
3237 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3238 if (beg > 0) return 0;
3239 len = 0;
3240 }
3241 else {
3242 len = str_offset(p, e, len, enc, 0);
3243 }
3244 end:
3245 *lenp = len;
3246 RB_GC_GUARD(str);
3247 return p;
3248}
3249
3250static VALUE str_substr(VALUE str, long beg, long len, int empty);
3251
3252VALUE
3253rb_str_substr(VALUE str, long beg, long len)
3254{
3255 return str_substr(str, beg, len, TRUE);
3256}
3257
3258VALUE
3259rb_str_substr_two_fixnums(VALUE str, VALUE beg, VALUE len, int empty)
3260{
3261 return str_substr(str, NUM2LONG(beg), NUM2LONG(len), empty);
3262}
3263
3264static VALUE
3265str_substr(VALUE str, long beg, long len, int empty)
3266{
3267 char *p = rb_str_subpos(str, beg, &len);
3268
3269 if (!p) return Qnil;
3270 if (!len && !empty) return Qnil;
3271
3272 beg = p - RSTRING_PTR(str);
3273
3274 VALUE str2 = str_subseq(str, beg, len);
3275 rb_enc_cr_str_copy_for_substr(str2, str);
3276 return str2;
3277}
3278
3279/* :nodoc: */
3280VALUE
3282{
3283 if (CHILLED_STRING_P(str)) {
3284 FL_UNSET_RAW(str, STR_CHILLED);
3285 }
3286
3287 if (OBJ_FROZEN(str)) return str;
3288 rb_str_resize(str, RSTRING_LEN(str));
3289 return rb_obj_freeze(str);
3290}
3291
3292/*
3293 * call-seq:
3294 * +string -> new_string or self
3295 *
3296 * Returns +self+ if +self+ is not frozen and can be mutated
3297 * without warning issuance.
3298 *
3299 * Otherwise returns <tt>self.dup</tt>, which is not frozen.
3300 *
3301 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@Freezing-2FUnfreezing].
3302 */
3303static VALUE
3304str_uplus(VALUE str)
3305{
3306 if (OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3307 return rb_str_dup(str);
3308 }
3309 else {
3310 return str;
3311 }
3312}
3313
3314/*
3315 * call-seq:
3316 * -self -> frozen_string
3317 *
3318 * Returns a frozen string equal to +self+.
3319 *
3320 * The returned string is +self+ if and only if all of the following are true:
3321 *
3322 * - +self+ is already frozen.
3323 * - +self+ is an instance of \String (rather than of a subclass of \String)
3324 * - +self+ has no instance variables set on it.
3325 *
3326 * Otherwise, the returned string is a frozen copy of +self+.
3327 *
3328 * Returning +self+, when possible, saves duplicating +self+;
3329 * see {Data deduplication}[https://en.wikipedia.org/wiki/Data_deduplication].
3330 *
3331 * It may also save duplicating other, already-existing, strings:
3332 *
3333 * s0 = 'foo'
3334 * s1 = 'foo'
3335 * s0.object_id == s1.object_id # => false
3336 * (-s0).object_id == (-s1).object_id # => true
3337 *
3338 * Note that method #-@ is convenient for defining a constant:
3339 *
3340 * FileName = -'config/database.yml'
3341 *
3342 * While its alias #dedup is better suited for chaining:
3343 *
3344 * 'foo'.dedup.gsub!('o')
3345 *
3346 * Related: see {Freezing/Unfreezing}[rdoc-ref:String@Freezing-2FUnfreezing].
3347 */
3348static VALUE
3349str_uminus(VALUE str)
3350{
3351 if (!BARE_STRING_P(str) && !rb_obj_frozen_p(str)) {
3352 str = rb_str_dup(str);
3353 }
3354 return rb_fstring(str);
3355}
3356
3357RUBY_ALIAS_FUNCTION(rb_str_dup_frozen(VALUE str), rb_str_new_frozen, (str))
3358#define rb_str_dup_frozen rb_str_new_frozen
3359
3360VALUE
3362{
3363 rb_check_frozen(str);
3364 if (FL_TEST(str, STR_TMPLOCK)) {
3365 rb_raise(rb_eRuntimeError, "temporal locking already locked string");
3366 }
3367 FL_SET(str, STR_TMPLOCK);
3368 return str;
3369}
3370
3371VALUE
3373{
3374 rb_check_frozen(str);
3375 if (!FL_TEST(str, STR_TMPLOCK)) {
3376 rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string");
3377 }
3378 FL_UNSET(str, STR_TMPLOCK);
3379 return str;
3380}
3381
3382VALUE
3383rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg)
3384{
3385 rb_str_locktmp(str);
3386 return rb_ensure(func, arg, rb_str_unlocktmp, str);
3387}
3388
3389void
3391{
3392 RUBY_ASSERT(ruby_thread_has_gvl_p());
3393
3394 long capa;
3395 const int termlen = TERM_LEN(str);
3396
3397 str_modifiable(str);
3398 if (STR_SHARED_P(str)) {
3399 rb_raise(rb_eRuntimeError, "can't set length of shared string");
3400 }
3401 if (len > (capa = (long)str_capacity(str, termlen)) || len < 0) {
3402 rb_bug("probable buffer overflow: %ld for %ld", len, capa);
3403 }
3404
3405 int cr = ENC_CODERANGE(str);
3406 if (len == 0) {
3407 /* Empty string does not contain non-ASCII */
3409 }
3410 else if (cr == ENC_CODERANGE_UNKNOWN) {
3411 /* Leave unknown. */
3412 }
3413 else if (len > RSTRING_LEN(str)) {
3414 if (ENC_CODERANGE_CLEAN_P(cr)) {
3415 /* Update the coderange regarding the extended part. */
3416 const char *const prev_end = RSTRING_END(str);
3417 const char *const new_end = RSTRING_PTR(str) + len;
3418 rb_encoding *enc = rb_enc_get(str);
3419 rb_str_coderange_scan_restartable(prev_end, new_end, enc, &cr);
3420 ENC_CODERANGE_SET(str, cr);
3421 }
3422 else if (cr == ENC_CODERANGE_BROKEN) {
3423 /* May be valid now, by appended part. */
3425 }
3426 }
3427 else if (len < RSTRING_LEN(str)) {
3428 if (cr != ENC_CODERANGE_7BIT) {
3429 /* ASCII-only string is keeping after truncated. Valid
3430 * and broken may be invalid or valid, leave unknown. */
3432 }
3433 }
3434
3435 STR_SET_LEN(str, len);
3436 TERM_FILL(&RSTRING_PTR(str)[len], termlen);
3437}
3438
3439VALUE
3440rb_str_resize(VALUE str, long len)
3441{
3442 if (len < 0) {
3443 rb_raise(rb_eArgError, "negative string size (or size too big)");
3444 }
3445
3446 int independent = str_independent(str);
3447 long slen = RSTRING_LEN(str);
3448 const int termlen = TERM_LEN(str);
3449
3450 if (slen > len || (termlen != 1 && slen < len)) {
3452 }
3453
3454 {
3455 long capa;
3456 if (STR_EMBED_P(str)) {
3457 if (len == slen) return str;
3458 if (str_embed_capa(str) >= len + termlen) {
3459 STR_SET_LEN(str, len);
3460 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3461 return str;
3462 }
3463 str_make_independent_expand(str, slen, len - slen, termlen);
3464 }
3465 else if (str_embed_capa(str) >= len + termlen) {
3466 char *ptr = STR_HEAP_PTR(str);
3467 STR_SET_EMBED(str);
3468 if (slen > len) slen = len;
3469 if (slen > 0) MEMCPY(RSTRING(str)->as.embed.ary, ptr, char, slen);
3470 TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
3471 STR_SET_LEN(str, len);
3472 if (independent) ruby_xfree(ptr);
3473 return str;
3474 }
3475 else if (!independent) {
3476 if (len == slen) return str;
3477 str_make_independent_expand(str, slen, len - slen, termlen);
3478 }
3479 else if ((capa = RSTRING(str)->as.heap.aux.capa) < len ||
3480 (capa - len) > (len < 1024 ? len : 1024)) {
3481 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
3482 (size_t)len + termlen, STR_HEAP_SIZE(str));
3483 RSTRING(str)->as.heap.aux.capa = len;
3484 }
3485 else if (len == slen) return str;
3486 STR_SET_LEN(str, len);
3487 TERM_FILL(RSTRING(str)->as.heap.ptr + len, termlen); /* sentinel */
3488 }
3489 return str;
3490}
3491
3492static void
3493str_ensure_available_capa(VALUE str, long len)
3494{
3495 str_modify_keep_cr(str);
3496
3497 const int termlen = TERM_LEN(str);
3498 long olen = RSTRING_LEN(str);
3499
3500 if (RB_UNLIKELY(olen > LONG_MAX - len)) {
3501 rb_raise(rb_eArgError, "string sizes too big");
3502 }
3503
3504 long total = olen + len;
3505 long capa = str_capacity(str, termlen);
3506
3507 if (capa < total) {
3508 if (total >= LONG_MAX / 2) {
3509 capa = total;
3510 }
3511 while (total > capa) {
3512 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3513 }
3514 RESIZE_CAPA_TERM(str, capa, termlen);
3515 }
3516}
3517
3518static VALUE
3519str_buf_cat4(VALUE str, const char *ptr, long len, bool keep_cr)
3520{
3521 if (keep_cr) {
3522 str_modify_keep_cr(str);
3523 }
3524 else {
3525 rb_str_modify(str);
3526 }
3527 if (len == 0) return 0;
3528
3529 long total, olen, off = -1;
3530 char *sptr;
3531 const int termlen = TERM_LEN(str);
3532
3533 RSTRING_GETMEM(str, sptr, olen);
3534 if (ptr >= sptr && ptr <= sptr + olen) {
3535 off = ptr - sptr;
3536 }
3537
3538 long capa = str_capacity(str, termlen);
3539
3540 if (olen > LONG_MAX - len) {
3541 rb_raise(rb_eArgError, "string sizes too big");
3542 }
3543 total = olen + len;
3544 if (capa < total) {
3545 if (total >= LONG_MAX / 2) {
3546 capa = total;
3547 }
3548 while (total > capa) {
3549 capa = 2 * capa + termlen; /* == 2*(capa+termlen)-termlen */
3550 }
3551 RESIZE_CAPA_TERM(str, capa, termlen);
3552 sptr = RSTRING_PTR(str);
3553 }
3554 if (off != -1) {
3555 ptr = sptr + off;
3556 }
3557 memcpy(sptr + olen, ptr, len);
3558 STR_SET_LEN(str, total);
3559 TERM_FILL(sptr + total, termlen); /* sentinel */
3560
3561 return str;
3562}
3563
3564#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3565#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3566
3567VALUE
3568rb_str_cat(VALUE str, const char *ptr, long len)
3569{
3570 if (len == 0) return str;
3571 if (len < 0) {
3572 rb_raise(rb_eArgError, "negative string size (or size too big)");
3573 }
3574 return str_buf_cat(str, ptr, len);
3575}
3576
3577VALUE
3578rb_str_cat_cstr(VALUE str, const char *ptr)
3579{
3580 must_not_null(ptr);
3581 return rb_str_buf_cat(str, ptr, strlen(ptr));
3582}
3583
3584static void
3585rb_str_buf_cat_byte(VALUE str, unsigned char byte)
3586{
3587 RUBY_ASSERT(RB_ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT || RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII);
3588
3589 // We can't write directly to shared strings without impacting others, so we must make the string independent.
3590 if (UNLIKELY(!str_independent(str))) {
3591 str_make_independent(str);
3592 }
3593
3594 long string_length = -1;
3595 const int null_terminator_length = 1;
3596 char *sptr;
3597 RSTRING_GETMEM(str, sptr, string_length);
3598
3599 // Ensure the resulting string wouldn't be too long.
3600 if (UNLIKELY(string_length > LONG_MAX - 1)) {
3601 rb_raise(rb_eArgError, "string sizes too big");
3602 }
3603
3604 long string_capacity = str_capacity(str, null_terminator_length);
3605
3606 // Get the code range before any modifications since those might clear the code range.
3607 int cr = ENC_CODERANGE(str);
3608
3609 // Check if the string has spare string_capacity to write the new byte.
3610 if (LIKELY(string_capacity >= string_length + 1)) {
3611 // In fast path we can write the new byte and note the string's new length.
3612 sptr[string_length] = byte;
3613 STR_SET_LEN(str, string_length + 1);
3614 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3615 }
3616 else {
3617 // If there's not enough string_capacity, make a call into the general string concatenation function.
3618 str_buf_cat(str, (char *)&byte, 1);
3619 }
3620
3621 // If the code range is already known, we can derive the resulting code range cheaply by looking at the byte we
3622 // just appended. If the code range is unknown, but the string was empty, then we can also derive the code range
3623 // by looking at the byte we just appended. Otherwise, we'd have to scan the bytes to determine the code range so
3624 // we leave it as unknown. It cannot be broken for binary strings so we don't need to handle that option.
3625 if (cr == ENC_CODERANGE_7BIT || string_length == 0) {
3626 if (ISASCII(byte)) {
3628 }
3629 else {
3631
3632 // Promote a US-ASCII string to ASCII-8BIT when a non-ASCII byte is appended.
3633 if (UNLIKELY(RB_ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)) {
3634 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3635 }
3636 }
3637 }
3638}
3639
3640RUBY_ALIAS_FUNCTION(rb_str_buf_cat(VALUE str, const char *ptr, long len), rb_str_cat, (str, ptr, len))
3641RUBY_ALIAS_FUNCTION(rb_str_buf_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3642RUBY_ALIAS_FUNCTION(rb_str_cat2(VALUE str, const char *ptr), rb_str_cat_cstr, (str, ptr))
3643
3644static VALUE
3645rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, long len,
3646 int ptr_encindex, int ptr_cr, int *ptr_cr_ret)
3647{
3648 int str_encindex = ENCODING_GET(str);
3649 int res_encindex;
3650 int str_cr, res_cr;
3651 rb_encoding *str_enc, *ptr_enc;
3652
3653 str_cr = RSTRING_LEN(str) ? ENC_CODERANGE(str) : ENC_CODERANGE_7BIT;
3654
3655 if (str_encindex == ptr_encindex) {
3656 if (str_cr != ENC_CODERANGE_UNKNOWN && ptr_cr == ENC_CODERANGE_UNKNOWN) {
3657 ptr_cr = coderange_scan(ptr, len, rb_enc_from_index(ptr_encindex));
3658 }
3659 }
3660 else {
3661 str_enc = rb_enc_from_index(str_encindex);
3662 ptr_enc = rb_enc_from_index(ptr_encindex);
3663 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3664 if (len == 0)
3665 return str;
3666 if (RSTRING_LEN(str) == 0) {
3667 rb_str_buf_cat(str, ptr, len);
3668 ENCODING_CODERANGE_SET(str, ptr_encindex, ptr_cr);
3669 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3670 return str;
3671 }
3672 goto incompatible;
3673 }
3674 if (ptr_cr == ENC_CODERANGE_UNKNOWN) {
3675 ptr_cr = coderange_scan(ptr, len, ptr_enc);
3676 }
3677 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3678 if (ENCODING_IS_ASCII8BIT(str) || ptr_cr != ENC_CODERANGE_7BIT) {
3679 str_cr = rb_enc_str_coderange(str);
3680 }
3681 }
3682 }
3683 if (ptr_cr_ret)
3684 *ptr_cr_ret = ptr_cr;
3685
3686 if (str_encindex != ptr_encindex &&
3687 str_cr != ENC_CODERANGE_7BIT &&
3688 ptr_cr != ENC_CODERANGE_7BIT) {
3689 str_enc = rb_enc_from_index(str_encindex);
3690 ptr_enc = rb_enc_from_index(ptr_encindex);
3691 goto incompatible;
3692 }
3693
3694 if (str_cr == ENC_CODERANGE_UNKNOWN) {
3695 res_encindex = str_encindex;
3696 res_cr = ENC_CODERANGE_UNKNOWN;
3697 }
3698 else if (str_cr == ENC_CODERANGE_7BIT) {
3699 if (ptr_cr == ENC_CODERANGE_7BIT) {
3700 res_encindex = str_encindex;
3701 res_cr = ENC_CODERANGE_7BIT;
3702 }
3703 else {
3704 res_encindex = ptr_encindex;
3705 res_cr = ptr_cr;
3706 }
3707 }
3708 else if (str_cr == ENC_CODERANGE_VALID) {
3709 res_encindex = str_encindex;
3710 if (ENC_CODERANGE_CLEAN_P(ptr_cr))
3711 res_cr = str_cr;
3712 else
3713 res_cr = ptr_cr;
3714 }
3715 else { /* str_cr == ENC_CODERANGE_BROKEN */
3716 res_encindex = str_encindex;
3717 res_cr = str_cr;
3718 if (0 < len) res_cr = ENC_CODERANGE_UNKNOWN;
3719 }
3720
3721 if (len < 0) {
3722 rb_raise(rb_eArgError, "negative string size (or size too big)");
3723 }
3724 str_buf_cat(str, ptr, len);
3725 ENCODING_CODERANGE_SET(str, res_encindex, res_cr);
3726 return str;
3727
3728 incompatible:
3729 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
3730 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3732}
3733
3734VALUE
3735rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *ptr_enc)
3736{
3737 return rb_enc_cr_str_buf_cat(str, ptr, len,
3738 rb_enc_to_index(ptr_enc), ENC_CODERANGE_UNKNOWN, NULL);
3739}
3740
3741VALUE
3743{
3744 /* ptr must reference NUL terminated ASCII string. */
3745 int encindex = ENCODING_GET(str);
3746 rb_encoding *enc = rb_enc_from_index(encindex);
3747 if (rb_enc_asciicompat(enc)) {
3748 return rb_enc_cr_str_buf_cat(str, ptr, strlen(ptr),
3749 encindex, ENC_CODERANGE_7BIT, 0);
3750 }
3751 else {
3752 char *buf = ALLOCA_N(char, rb_enc_mbmaxlen(enc));
3753 while (*ptr) {
3754 unsigned int c = (unsigned char)*ptr;
3755 int len = rb_enc_codelen(c, enc);
3756 rb_enc_mbcput(c, buf, enc);
3757 rb_enc_cr_str_buf_cat(str, buf, len,
3758 encindex, ENC_CODERANGE_VALID, 0);
3759 ptr++;
3760 }
3761 return str;
3762 }
3763}
3764
3765VALUE
3767{
3768 int str2_cr = rb_enc_str_coderange(str2);
3769
3770 if (str_enc_fastpath(str)) {
3771 switch (str2_cr) {
3772 case ENC_CODERANGE_7BIT:
3773 // If RHS is 7bit we can do simple concatenation
3774 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3775 RB_GC_GUARD(str2);
3776 return str;
3778 // If RHS is valid, we can do simple concatenation if encodings are the same
3779 if (ENCODING_GET_INLINED(str) == ENCODING_GET_INLINED(str2)) {
3780 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2), true);
3781 int str_cr = ENC_CODERANGE(str);
3782 if (UNLIKELY(str_cr != ENC_CODERANGE_VALID)) {
3783 ENC_CODERANGE_SET(str, RB_ENC_CODERANGE_AND(str_cr, str2_cr));
3784 }
3785 RB_GC_GUARD(str2);
3786 return str;
3787 }
3788 }
3789 }
3790
3791 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3792 ENCODING_GET(str2), str2_cr, &str2_cr);
3793
3794 ENC_CODERANGE_SET(str2, str2_cr);
3795
3796 return str;
3797}
3798
3799VALUE
3801{
3802 StringValue(str2);
3803 return rb_str_buf_append(str, str2);
3804}
3805
3806VALUE
3807rb_str_concat_literals(size_t num, const VALUE *strary)
3808{
3809 VALUE str;
3810 size_t i, s = 0;
3811 unsigned long len = 1;
3812
3813 if (UNLIKELY(!num)) return rb_str_new(0, 0);
3814 if (UNLIKELY(num == 1)) return rb_str_resurrect(strary[0]);
3815
3816 for (i = 0; i < num; ++i) { len += RSTRING_LEN(strary[i]); }
3817 str = rb_str_buf_new(len);
3818 str_enc_copy_direct(str, strary[0]);
3819
3820 for (i = s; i < num; ++i) {
3821 const VALUE v = strary[i];
3822 int encidx = ENCODING_GET(v);
3823
3824 rb_str_buf_append(str, v);
3825 if (encidx != ENCINDEX_US_ASCII) {
3826 if (ENCODING_GET_INLINED(str) == ENCINDEX_US_ASCII)
3827 rb_enc_set_index(str, encidx);
3828 }
3829 }
3830 return str;
3831}
3832
3833/*
3834 * call-seq:
3835 * concat(*objects) -> string
3836 *
3837 * :include: doc/string/concat.rdoc
3838 */
3839static VALUE
3840rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
3841{
3842 str_modifiable(str);
3843
3844 if (argc == 1) {
3845 return rb_str_concat(str, argv[0]);
3846 }
3847 else if (argc > 1) {
3848 int i;
3849 VALUE arg_str = rb_str_tmp_new(0);
3850 rb_enc_copy(arg_str, str);
3851 for (i = 0; i < argc; i++) {
3852 rb_str_concat(arg_str, argv[i]);
3853 }
3854 rb_str_buf_append(str, arg_str);
3855 }
3856
3857 return str;
3858}
3859
3860/*
3861 * call-seq:
3862 * append_as_bytes(*objects) -> self
3863 *
3864 * Concatenates each object in +objects+ into +self+; returns +self+;
3865 * performs no encoding validation or conversion:
3866 *
3867 * s = 'foo'
3868 * s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82"
3869 * s.valid_encoding? # => false
3870 * s.append_as_bytes("\xAC 12")
3871 * s.valid_encoding? # => true
3872 *
3873 * When a given object is an integer,
3874 * the value is considered an 8-bit byte;
3875 * if the integer occupies more than one byte (i.e,. is greater than 255),
3876 * appends only the low-order byte (similar to String#setbyte):
3877 *
3878 * s = ""
3879 * s.append_as_bytes(0, 257) # => "\u0000\u0001"
3880 * s.bytesize # => 2
3881 *
3882 * Related: see {Modifying}[rdoc-ref:String@Modifying].
3883 */
3884
3885VALUE
3886rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
3887{
3888 long needed_capacity = 0;
3889 volatile VALUE t0;
3890 enum ruby_value_type *types = ALLOCV_N(enum ruby_value_type, t0, argc);
3891
3892 for (int index = 0; index < argc; index++) {
3893 VALUE obj = argv[index];
3894 enum ruby_value_type type = types[index] = rb_type(obj);
3895 switch (type) {
3896 case T_FIXNUM:
3897 case T_BIGNUM:
3898 needed_capacity++;
3899 break;
3900 case T_STRING:
3901 needed_capacity += RSTRING_LEN(obj);
3902 break;
3903 default:
3904 rb_raise(
3906 "wrong argument type %"PRIsVALUE" (expected String or Integer)",
3907 rb_obj_class(obj)
3908 );
3909 break;
3910 }
3911 }
3912
3913 str_ensure_available_capa(str, needed_capacity);
3914 char *sptr = RSTRING_END(str);
3915
3916 for (int index = 0; index < argc; index++) {
3917 VALUE obj = argv[index];
3918 enum ruby_value_type type = types[index];
3919 switch (type) {
3920 case T_FIXNUM:
3921 case T_BIGNUM: {
3922 argv[index] = obj = rb_int_and(obj, INT2FIX(0xff));
3923 char byte = (char)(NUM2INT(obj) & 0xFF);
3924 *sptr = byte;
3925 sptr++;
3926 break;
3927 }
3928 case T_STRING: {
3929 const char *ptr;
3930 long len;
3931 RSTRING_GETMEM(obj, ptr, len);
3932 memcpy(sptr, ptr, len);
3933 sptr += len;
3934 break;
3935 }
3936 default:
3937 rb_bug("append_as_bytes arguments should have been validated");
3938 }
3939 }
3940
3941 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
3942 TERM_FILL(sptr, TERM_LEN(str)); /* sentinel */
3943
3944 int cr = ENC_CODERANGE(str);
3945 switch (cr) {
3946 case ENC_CODERANGE_7BIT: {
3947 for (int index = 0; index < argc; index++) {
3948 VALUE obj = argv[index];
3949 enum ruby_value_type type = types[index];
3950 switch (type) {
3951 case T_FIXNUM:
3952 case T_BIGNUM: {
3953 if (!ISASCII(NUM2INT(obj))) {
3954 goto clear_cr;
3955 }
3956 break;
3957 }
3958 case T_STRING: {
3959 if (ENC_CODERANGE(obj) != ENC_CODERANGE_7BIT) {
3960 goto clear_cr;
3961 }
3962 break;
3963 }
3964 default:
3965 rb_bug("append_as_bytes arguments should have been validated");
3966 }
3967 }
3968 break;
3969 }
3971 if (ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT) {
3972 goto keep_cr;
3973 }
3974 else {
3975 goto clear_cr;
3976 }
3977 break;
3978 default:
3979 goto clear_cr;
3980 break;
3981 }
3982
3983 RB_GC_GUARD(t0);
3984
3985 clear_cr:
3986 // If no fast path was hit, we clear the coderange.
3987 // append_as_bytes is predominantly meant to be used in
3988 // buffering situation, hence it's likely the coderange
3989 // will never be scanned, so it's not worth spending time
3990 // precomputing the coderange except for simple and common
3991 // situations.
3993 keep_cr:
3994 return str;
3995}
3996
3997/*
3998 * call-seq:
3999 * self << object -> self
4000 *
4001 * Appends a string representation of +object+ to +self+;
4002 * returns +self+.
4003 *
4004 * If +object+ is a string, appends it to +self+:
4005 *
4006 * s = 'foo'
4007 * s << 'bar' # => "foobar"
4008 * s # => "foobar"
4009 *
4010 * If +object+ is an integer,
4011 * its value is considered a codepoint;
4012 * converts the value to a character before concatenating:
4013 *
4014 * s = 'foo'
4015 * s << 33 # => "foo!"
4016 *
4017 * Additionally, if the codepoint is in range <tt>0..0xff</tt>
4018 * and the encoding of +self+ is Encoding::US_ASCII,
4019 * changes the encoding to Encoding::ASCII_8BIT:
4020 *
4021 * s = 'foo'.encode(Encoding::US_ASCII)
4022 * s.encoding # => #<Encoding:US-ASCII>
4023 * s << 0xff # => "foo\xFF"
4024 * s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
4025 *
4026 * Raises RangeError if that codepoint is not representable in the encoding of +self+:
4027 *
4028 * s = 'foo'
4029 * s.encoding # => <Encoding:UTF-8>
4030 * s << 0x00110000 # 1114112 out of char range (RangeError)
4031 * s = 'foo'.encode(Encoding::EUC_JP)
4032 * s << 0x00800080 # invalid codepoint 0x800080 in EUC-JP (RangeError)
4033 *
4034 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4035 */
4036VALUE
4038{
4039 unsigned int code;
4040 rb_encoding *enc = STR_ENC_GET(str1);
4041 int encidx;
4042
4043 if (RB_INTEGER_TYPE_P(str2)) {
4044 if (rb_num_to_uint(str2, &code) == 0) {
4045 }
4046 else if (FIXNUM_P(str2)) {
4047 rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(str2));
4048 }
4049 else {
4050 rb_raise(rb_eRangeError, "bignum out of char range");
4051 }
4052 }
4053 else {
4054 return rb_str_append(str1, str2);
4055 }
4056
4057 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4058
4059 if (encidx >= 0) {
4060 rb_str_buf_cat_byte(str1, (unsigned char)code);
4061 }
4062 else {
4063 long pos = RSTRING_LEN(str1);
4064 int cr = ENC_CODERANGE(str1);
4065 int len;
4066 char *buf;
4067
4068 switch (len = rb_enc_codelen(code, enc)) {
4069 case ONIGERR_INVALID_CODE_POINT_VALUE:
4070 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4071 break;
4072 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4073 case 0:
4074 rb_raise(rb_eRangeError, "%u out of char range", code);
4075 break;
4076 }
4077 buf = ALLOCA_N(char, len + 1);
4078 rb_enc_mbcput(code, buf, enc);
4079 if (rb_enc_precise_mbclen(buf, buf + len + 1, enc) != len) {
4080 rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4081 }
4082 rb_str_resize(str1, pos+len);
4083 memcpy(RSTRING_PTR(str1) + pos, buf, len);
4084 if (cr == ENC_CODERANGE_7BIT && code > 127) {
4086 }
4087 else if (cr == ENC_CODERANGE_BROKEN) {
4089 }
4090 ENC_CODERANGE_SET(str1, cr);
4091 }
4092 return str1;
4093}
4094
4095int
4096rb_ascii8bit_appendable_encoding_index(rb_encoding *enc, unsigned int code)
4097{
4098 int encidx = rb_enc_to_index(enc);
4099
4100 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4101 /* US-ASCII automatically extended to ASCII-8BIT */
4102 if (code > 0xFF) {
4103 rb_raise(rb_eRangeError, "%u out of char range", code);
4104 }
4105 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4106 return ENCINDEX_ASCII_8BIT;
4107 }
4108 return encidx;
4109 }
4110 else {
4111 return -1;
4112 }
4113}
4114
4115/*
4116 * call-seq:
4117 * prepend(*other_strings) -> new_string
4118 *
4119 * Prefixes to +self+ the concatenation of the given +other_strings+; returns +self+:
4120 *
4121 * 'baz'.prepend('foo', 'bar') # => "foobarbaz"
4122 *
4123 * Related: see {Modifying}[rdoc-ref:String@Modifying].
4124 *
4125 */
4126
4127static VALUE
4128rb_str_prepend_multi(int argc, VALUE *argv, VALUE str)
4129{
4130 str_modifiable(str);
4131
4132 if (argc == 1) {
4133 rb_str_update(str, 0L, 0L, argv[0]);
4134 }
4135 else if (argc > 1) {
4136 int i;
4137 VALUE arg_str = rb_str_tmp_new(0);
4138 rb_enc_copy(arg_str, str);
4139 for (i = 0; i < argc; i++) {
4140 rb_str_append(arg_str, argv[i]);
4141 }
4142 rb_str_update(str, 0L, 0L, arg_str);
4143 }
4144
4145 return str;
4146}
4147
4148st_index_t
4150{
4151 if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) {
4152 st_index_t precomputed_hash;
4153 memcpy(&precomputed_hash, RSTRING_END(str) + TERM_LEN(str), sizeof(precomputed_hash));
4154
4155 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4156 return precomputed_hash;
4157 }
4158
4159 return str_do_hash(str);
4160}
4161
4162int
4164{
4165 long len1, len2;
4166 const char *ptr1, *ptr2;
4167 RSTRING_GETMEM(str1, ptr1, len1);
4168 RSTRING_GETMEM(str2, ptr2, len2);
4169 return (len1 != len2 ||
4170 !rb_str_comparable(str1, str2) ||
4171 memcmp(ptr1, ptr2, len1) != 0);
4172}
4173
4174/*
4175 * call-seq:
4176 * hash -> integer
4177 *
4178 * :include: doc/string/hash.rdoc
4179 *
4180 */
4181
4182static VALUE
4183rb_str_hash_m(VALUE str)
4184{
4185 st_index_t hval = rb_str_hash(str);
4186 return ST2FIX(hval);
4187}
4188
4189#define lesser(a,b) (((a)>(b))?(b):(a))
4190
4191int
4193{
4194 int idx1, idx2;
4195 int rc1, rc2;
4196
4197 if (RSTRING_LEN(str1) == 0) return TRUE;
4198 if (RSTRING_LEN(str2) == 0) return TRUE;
4199 idx1 = ENCODING_GET(str1);
4200 idx2 = ENCODING_GET(str2);
4201 if (idx1 == idx2) return TRUE;
4202 rc1 = rb_enc_str_coderange(str1);
4203 rc2 = rb_enc_str_coderange(str2);
4204 if (rc1 == ENC_CODERANGE_7BIT) {
4205 if (rc2 == ENC_CODERANGE_7BIT) return TRUE;
4206 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4207 return TRUE;
4208 }
4209 if (rc2 == ENC_CODERANGE_7BIT) {
4210 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4211 return TRUE;
4212 }
4213 return FALSE;
4214}
4215
4216int
4218{
4219 long len1, len2;
4220 const char *ptr1, *ptr2;
4221 int retval;
4222
4223 if (str1 == str2) return 0;
4224 RSTRING_GETMEM(str1, ptr1, len1);
4225 RSTRING_GETMEM(str2, ptr2, len2);
4226 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4227 if (len1 == len2) {
4228 if (!rb_str_comparable(str1, str2)) {
4229 if (ENCODING_GET(str1) > ENCODING_GET(str2))
4230 return 1;
4231 return -1;
4232 }
4233 return 0;
4234 }
4235 if (len1 > len2) return 1;
4236 return -1;
4237 }
4238 if (retval > 0) return 1;
4239 return -1;
4240}
4241
4242/*
4243 * call-seq:
4244 * self == object -> true or false
4245 *
4246 * Returns whether +object+ is equal to +self+.
4247 *
4248 * When +object+ is a string, returns whether +object+ has the same length and content as +self+:
4249 *
4250 * s = 'foo'
4251 * s == 'foo' # => true
4252 * s == 'food' # => false
4253 * s == 'FOO' # => false
4254 *
4255 * Returns +false+ if the two strings' encodings are not compatible:
4256 *
4257 * "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false
4258 *
4259 * When +object+ is not a string:
4260 *
4261 * - If +object+ responds to method <tt>to_str</tt>,
4262 * <tt>object == self</tt> is called and its return value is returned.
4263 * - If +object+ does not respond to <tt>to_str</tt>,
4264 * +false+ is returned.
4265 *
4266 * Related: {Comparing}[rdoc-ref:String@Comparing].
4267 */
4268
4269VALUE
4271{
4272 if (str1 == str2) return Qtrue;
4273 if (!RB_TYPE_P(str2, T_STRING)) {
4274 if (!rb_respond_to(str2, idTo_str)) {
4275 return Qfalse;
4276 }
4277 return rb_equal(str2, str1);
4278 }
4279 return rb_str_eql_internal(str1, str2);
4280}
4281
4282/*
4283 * call-seq:
4284 * eql?(object) -> true or false
4285 *
4286 * :include: doc/string/eql_p.rdoc
4287 *
4288 */
4289
4290VALUE
4291rb_str_eql(VALUE str1, VALUE str2)
4292{
4293 if (str1 == str2) return Qtrue;
4294 if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
4295 return rb_str_eql_internal(str1, str2);
4296}
4297
4298/*
4299 * call-seq:
4300 * self <=> other -> -1, 0, 1, or nil
4301 *
4302 * Compares +self+ and +other+,
4303 * evaluating their _contents_, not their _lengths_.
4304 *
4305 * Returns:
4306 *
4307 * - +-1+, if +self+ is smaller.
4308 * - +0+, if the two are equal.
4309 * - +1+, if +self+ is larger.
4310 * - +nil+, if the two are incomparable.
4311 *
4312 * Examples:
4313 *
4314 * 'a' <=> 'b' # => -1
4315 * 'a' <=> 'ab' # => -1
4316 * 'a' <=> 'a' # => 0
4317 * 'b' <=> 'a' # => 1
4318 * 'ab' <=> 'a' # => 1
4319 * 'a' <=> :a # => nil
4320 *
4321 * \Class \String includes module Comparable,
4322 * each of whose methods uses String#<=> for comparison.
4323 *
4324 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4325 */
4326
4327static VALUE
4328rb_str_cmp_m(VALUE str1, VALUE str2)
4329{
4330 int result;
4331 VALUE s = rb_check_string_type(str2);
4332 if (NIL_P(s)) {
4333 return rb_invcmp(str1, str2);
4334 }
4335 result = rb_str_cmp(str1, s);
4336 return INT2FIX(result);
4337}
4338
4339static VALUE str_casecmp(VALUE str1, VALUE str2);
4340static VALUE str_casecmp_p(VALUE str1, VALUE str2);
4341
4342/*
4343 * call-seq:
4344 * casecmp(other_string) -> -1, 0, 1, or nil
4345 *
4346 * Ignoring case, compares +self+ and +other_string+; returns:
4347 *
4348 * - -1 if <tt>self.downcase</tt> is smaller than <tt>other_string.downcase</tt>.
4349 * - 0 if the two are equal.
4350 * - 1 if <tt>self.downcase</tt> is larger than <tt>other_string.downcase</tt>.
4351 * - +nil+ if the two are incomparable.
4352 *
4353 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4354 *
4355 * Examples:
4356 *
4357 * 'foo'.casecmp('goo') # => -1
4358 * 'goo'.casecmp('foo') # => 1
4359 * 'foo'.casecmp('food') # => -1
4360 * 'food'.casecmp('foo') # => 1
4361 * 'FOO'.casecmp('foo') # => 0
4362 * 'foo'.casecmp('FOO') # => 0
4363 * 'foo'.casecmp(1) # => nil
4364 *
4365 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4366 */
4367
4368static VALUE
4369rb_str_casecmp(VALUE str1, VALUE str2)
4370{
4371 VALUE s = rb_check_string_type(str2);
4372 if (NIL_P(s)) {
4373 return Qnil;
4374 }
4375 return str_casecmp(str1, s);
4376}
4377
4378static VALUE
4379str_casecmp(VALUE str1, VALUE str2)
4380{
4381 long len;
4382 rb_encoding *enc;
4383 const char *p1, *p1end, *p2, *p2end;
4384
4385 enc = rb_enc_compatible(str1, str2);
4386 if (!enc) {
4387 return Qnil;
4388 }
4389
4390 p1 = RSTRING_PTR(str1); p1end = RSTRING_END(str1);
4391 p2 = RSTRING_PTR(str2); p2end = RSTRING_END(str2);
4392 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4393 while (p1 < p1end && p2 < p2end) {
4394 if (*p1 != *p2) {
4395 unsigned int c1 = TOLOWER(*p1 & 0xff);
4396 unsigned int c2 = TOLOWER(*p2 & 0xff);
4397 if (c1 != c2)
4398 return INT2FIX(c1 < c2 ? -1 : 1);
4399 }
4400 p1++;
4401 p2++;
4402 }
4403 }
4404 else {
4405 while (p1 < p1end && p2 < p2end) {
4406 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4407 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4408
4409 if (0 <= c1 && 0 <= c2) {
4410 c1 = TOLOWER(c1);
4411 c2 = TOLOWER(c2);
4412 if (c1 != c2)
4413 return INT2FIX(c1 < c2 ? -1 : 1);
4414 }
4415 else {
4416 int r;
4417 l1 = rb_enc_mbclen(p1, p1end, enc);
4418 l2 = rb_enc_mbclen(p2, p2end, enc);
4419 len = l1 < l2 ? l1 : l2;
4420 r = memcmp(p1, p2, len);
4421 if (r != 0)
4422 return INT2FIX(r < 0 ? -1 : 1);
4423 if (l1 != l2)
4424 return INT2FIX(l1 < l2 ? -1 : 1);
4425 }
4426 p1 += l1;
4427 p2 += l2;
4428 }
4429 }
4430 if (p1 == p1end && p2 == p2end) return INT2FIX(0);
4431 if (p1 == p1end) return INT2FIX(-1);
4432 return INT2FIX(1);
4433}
4434
4435/*
4436 * call-seq:
4437 * casecmp?(other_string) -> true, false, or nil
4438 *
4439 * Returns +true+ if +self+ and +other_string+ are equal after
4440 * Unicode case folding, +false+ if unequal, +nil+ if incomparable.
4441 *
4442 * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
4443 *
4444 * Examples:
4445 *
4446 * 'foo'.casecmp?('goo') # => false
4447 * 'goo'.casecmp?('foo') # => false
4448 * 'foo'.casecmp?('food') # => false
4449 * 'food'.casecmp?('foo') # => false
4450 * 'FOO'.casecmp?('foo') # => true
4451 * 'foo'.casecmp?('FOO') # => true
4452 * 'foo'.casecmp?(1) # => nil
4453 *
4454 * Related: see {Comparing}[rdoc-ref:String@Comparing].
4455 */
4456
4457static VALUE
4458rb_str_casecmp_p(VALUE str1, VALUE str2)
4459{
4460 VALUE s = rb_check_string_type(str2);
4461 if (NIL_P(s)) {
4462 return Qnil;
4463 }
4464 return str_casecmp_p(str1, s);
4465}
4466
4467static VALUE
4468str_casecmp_p(VALUE str1, VALUE str2)
4469{
4470 rb_encoding *enc;
4471 VALUE folded_str1, folded_str2;
4472 VALUE fold_opt = sym_fold;
4473
4474 enc = rb_enc_compatible(str1, str2);
4475 if (!enc) {
4476 return Qnil;
4477 }
4478
4479 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4480 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4481
4482 return rb_str_eql(folded_str1, folded_str2);
4483}
4484
4485static long
4486strseq_core(const char *str_ptr, const char *str_ptr_end, long str_len,
4487 const char *sub_ptr, long sub_len, long offset, rb_encoding *enc)
4488{
4489 const char *search_start = str_ptr;
4490 long pos, search_len = str_len - offset;
4491
4492 for (;;) {
4493 const char *t;
4494 pos = rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4495 if (pos < 0) return pos;
4496 t = rb_enc_right_char_head(search_start, search_start+pos, str_ptr_end, enc);
4497 if (t == search_start + pos) break;
4498 search_len -= t - search_start;
4499 if (search_len <= 0) return -1;
4500 offset += t - search_start;
4501 search_start = t;
4502 }
4503 return pos + offset;
4504}
4505
4506/* found index in byte */
4507#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4508#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4509
4510static long
4511rb_strseq_index(VALUE str, VALUE sub, long offset, int in_byte)
4512{
4513 const char *str_ptr, *str_ptr_end, *sub_ptr;
4514 long str_len, sub_len;
4515 rb_encoding *enc;
4516
4517 enc = rb_enc_check(str, sub);
4518 if (is_broken_string(sub)) return -1;
4519
4520 str_ptr = RSTRING_PTR(str);
4521 str_ptr_end = RSTRING_END(str);
4522 str_len = RSTRING_LEN(str);
4523 sub_ptr = RSTRING_PTR(sub);
4524 sub_len = RSTRING_LEN(sub);
4525
4526 if (str_len < sub_len) return -1;
4527
4528 if (offset != 0) {
4529 long str_len_char, sub_len_char;
4530 int single_byte = single_byte_optimizable(str);
4531 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4532 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4533 if (offset < 0) {
4534 offset += str_len_char;
4535 if (offset < 0) return -1;
4536 }
4537 if (str_len_char - offset < sub_len_char) return -1;
4538 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4539 str_ptr += offset;
4540 }
4541 if (sub_len == 0) return offset;
4542
4543 /* need proceed one character at a time */
4544 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4545}
4546
4547
4548/*
4549 * call-seq:
4550 * index(pattern, offset = 0) -> integer or nil
4551 *
4552 * :include: doc/string/index.rdoc
4553 *
4554 */
4555
4556static VALUE
4557rb_str_index_m(int argc, VALUE *argv, VALUE str)
4558{
4559 VALUE sub;
4560 VALUE initpos;
4561 rb_encoding *enc = STR_ENC_GET(str);
4562 long pos;
4563
4564 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4565 long slen = str_strlen(str, enc); /* str's enc */
4566 pos = NUM2LONG(initpos);
4567 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4568 if (RB_TYPE_P(sub, T_REGEXP)) {
4570 }
4571 return Qnil;
4572 }
4573 }
4574 else {
4575 pos = 0;
4576 }
4577
4578 if (RB_TYPE_P(sub, T_REGEXP)) {
4579 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4580 enc, single_byte_optimizable(str));
4581
4582 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4583 VALUE match = rb_backref_get();
4584 struct re_registers *regs = RMATCH_REGS(match);
4585 pos = rb_str_sublen(str, BEG(0));
4586 return LONG2NUM(pos);
4587 }
4588 }
4589 else {
4590 StringValue(sub);
4591 pos = rb_str_index(str, sub, pos);
4592 if (pos >= 0) {
4593 pos = rb_str_sublen(str, pos);
4594 return LONG2NUM(pos);
4595 }
4596 }
4597 return Qnil;
4598}
4599
4600/* Ensure that the given pos is a valid character boundary.
4601 * Note that in this function, "character" means a code point
4602 * (Unicode scalar value), not a grapheme cluster.
4603 */
4604static void
4605str_ensure_byte_pos(VALUE str, long pos)
4606{
4607 if (!single_byte_optimizable(str)) {
4608 const char *s = RSTRING_PTR(str);
4609 const char *e = RSTRING_END(str);
4610 const char *p = s + pos;
4611 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4612 rb_raise(rb_eIndexError,
4613 "offset %ld does not land on character boundary", pos);
4614 }
4615 }
4616}
4617
4618/*
4619 * call-seq:
4620 * byteindex(object, offset = 0) -> integer or nil
4621 *
4622 * Returns the 0-based integer index of a substring of +self+
4623 * specified by +object+ (a string or Regexp) and +offset+,
4624 * or +nil+ if there is no such substring;
4625 * the returned index is the count of _bytes_ (not characters).
4626 *
4627 * When +object+ is a string,
4628 * returns the index of the first found substring equal to +object+:
4629 *
4630 * s = 'foo' # => "foo"
4631 * s.size # => 3 # Three 1-byte characters.
4632 * s.bytesize # => 3 # Three bytes.
4633 * s.byteindex('f') # => 0
4634 * s.byteindex('o') # => 1
4635 * s.byteindex('oo') # => 1
4636 * s.byteindex('ooo') # => nil
4637 *
4638 * When +object+ is a Regexp,
4639 * returns the index of the first found substring matching +object+;
4640 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
4641 *
4642 * s = 'foo'
4643 * s.byteindex(/f/) # => 0
4644 * $~ # => #<MatchData "f">
4645 * s.byteindex(/o/) # => 1
4646 * s.byteindex(/oo/) # => 1
4647 * s.byteindex(/ooo/) # => nil
4648 * $~ # => nil
4649 *
4650 * \Integer argument +offset+, if given, specifies the 0-based index
4651 * of the byte where searching is to begin.
4652 *
4653 * When +offset+ is non-negative,
4654 * searching begins at byte position +offset+:
4655 *
4656 * s = 'foo'
4657 * s.byteindex('o', 1) # => 1
4658 * s.byteindex('o', 2) # => 2
4659 * s.byteindex('o', 3) # => nil
4660 *
4661 * When +offset+ is negative, counts backward from the end of +self+:
4662 *
4663 * s = 'foo'
4664 * s.byteindex('o', -1) # => 2
4665 * s.byteindex('o', -2) # => 1
4666 * s.byteindex('o', -3) # => 1
4667 * s.byteindex('o', -4) # => nil
4668 *
4669 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
4670 *
4671 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
4672 * s.size # => 2 # Two 3-byte characters.
4673 * s.bytesize # => 6 # Six bytes.
4674 * s.byteindex("\uFFFF") # => 0
4675 * s.byteindex("\uFFFF", 1) # Raises IndexError
4676 * s.byteindex("\uFFFF", 2) # Raises IndexError
4677 * s.byteindex("\uFFFF", 3) # => 3
4678 * s.byteindex("\uFFFF", 4) # Raises IndexError
4679 * s.byteindex("\uFFFF", 5) # Raises IndexError
4680 * s.byteindex("\uFFFF", 6) # => nil
4681 *
4682 * Related: see {Querying}[rdoc-ref:String@Querying].
4683 */
4684
4685static VALUE
4686rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
4687{
4688 VALUE sub;
4689 VALUE initpos;
4690 long pos;
4691
4692 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4693 long slen = RSTRING_LEN(str);
4694 pos = NUM2LONG(initpos);
4695 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4696 if (RB_TYPE_P(sub, T_REGEXP)) {
4698 }
4699 return Qnil;
4700 }
4701 }
4702 else {
4703 pos = 0;
4704 }
4705
4706 str_ensure_byte_pos(str, pos);
4707
4708 if (RB_TYPE_P(sub, T_REGEXP)) {
4709 if (rb_reg_search(sub, str, pos, 0) >= 0) {
4710 VALUE match = rb_backref_get();
4711 struct re_registers *regs = RMATCH_REGS(match);
4712 pos = BEG(0);
4713 return LONG2NUM(pos);
4714 }
4715 }
4716 else {
4717 StringValue(sub);
4718 pos = rb_str_byteindex(str, sub, pos);
4719 if (pos >= 0) return LONG2NUM(pos);
4720 }
4721 return Qnil;
4722}
4723
4724#ifndef HAVE_MEMRCHR
4725static void*
4726memrchr(const char *search_str, int chr, long search_len)
4727{
4728 const char *ptr = search_str + search_len;
4729 while (ptr > search_str) {
4730 if ((unsigned char)*(--ptr) == chr) return (void *)ptr;
4731 }
4732
4733 return ((void *)0);
4734}
4735#endif
4736
4737static long
4738str_rindex(VALUE str, VALUE sub, const char *s, rb_encoding *enc)
4739{
4740 char *hit, *adjusted;
4741 int c;
4742 long slen, searchlen;
4743 char *sbeg, *e, *t;
4744
4745 sbeg = RSTRING_PTR(str);
4746 slen = RSTRING_LEN(sub);
4747 if (slen == 0) return s - sbeg;
4748 e = RSTRING_END(str);
4749 t = RSTRING_PTR(sub);
4750 c = *t & 0xff;
4751 searchlen = s - sbeg + 1;
4752
4753 if (memcmp(s, t, slen) == 0) {
4754 return s - sbeg;
4755 }
4756
4757 do {
4758 hit = memrchr(sbeg, c, searchlen);
4759 if (!hit) break;
4760 adjusted = rb_enc_left_char_head(sbeg, hit, e, enc);
4761 if (hit != adjusted) {
4762 searchlen = adjusted - sbeg;
4763 continue;
4764 }
4765 if (memcmp(hit, t, slen) == 0)
4766 return hit - sbeg;
4767 searchlen = adjusted - sbeg;
4768 } while (searchlen > 0);
4769
4770 return -1;
4771}
4772
4773/* found index in byte */
4774static long
4775rb_str_rindex(VALUE str, VALUE sub, long pos)
4776{
4777 long len, slen;
4778 char *sbeg, *s;
4779 rb_encoding *enc;
4780 int singlebyte;
4781
4782 enc = rb_enc_check(str, sub);
4783 if (is_broken_string(sub)) return -1;
4784 singlebyte = single_byte_optimizable(str);
4785 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc); /* rb_enc_check */
4786 slen = str_strlen(sub, enc); /* rb_enc_check */
4787
4788 /* substring longer than string */
4789 if (len < slen) return -1;
4790 if (len - pos < slen) pos = len - slen;
4791 if (len == 0) return pos;
4792
4793 sbeg = RSTRING_PTR(str);
4794
4795 if (pos == 0) {
4796 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4797 return 0;
4798 else
4799 return -1;
4800 }
4801
4802 s = str_nth(sbeg, RSTRING_END(str), pos, enc, singlebyte);
4803 return str_rindex(str, sub, s, enc);
4804}
4805
4806/*
4807 * call-seq:
4808 * rindex(pattern, offset = self.length) -> integer or nil
4809 *
4810 * :include:doc/string/rindex.rdoc
4811 *
4812 */
4813
4814static VALUE
4815rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
4816{
4817 VALUE sub;
4818 VALUE initpos;
4819 rb_encoding *enc = STR_ENC_GET(str);
4820 long pos, len = str_strlen(str, enc); /* str's enc */
4821
4822 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4823 pos = NUM2LONG(initpos);
4824 if (pos < 0 && (pos += len) < 0) {
4825 if (RB_TYPE_P(sub, T_REGEXP)) {
4827 }
4828 return Qnil;
4829 }
4830 if (pos > len) pos = len;
4831 }
4832 else {
4833 pos = len;
4834 }
4835
4836 if (RB_TYPE_P(sub, T_REGEXP)) {
4837 /* enc = rb_enc_check(str, sub); */
4838 pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
4839 enc, single_byte_optimizable(str));
4840
4841 if (rb_reg_search(sub, str, pos, 1) >= 0) {
4842 VALUE match = rb_backref_get();
4843 struct re_registers *regs = RMATCH_REGS(match);
4844 pos = rb_str_sublen(str, BEG(0));
4845 return LONG2NUM(pos);
4846 }
4847 }
4848 else {
4849 StringValue(sub);
4850 pos = rb_str_rindex(str, sub, pos);
4851 if (pos >= 0) {
4852 pos = rb_str_sublen(str, pos);
4853 return LONG2NUM(pos);
4854 }
4855 }
4856 return Qnil;
4857}
4858
4859static long
4860rb_str_byterindex(VALUE str, VALUE sub, long pos)
4861{
4862 long len, slen;
4863 char *sbeg, *s;
4864 rb_encoding *enc;
4865
4866 enc = rb_enc_check(str, sub);
4867 if (is_broken_string(sub)) return -1;
4868 len = RSTRING_LEN(str);
4869 slen = RSTRING_LEN(sub);
4870
4871 /* substring longer than string */
4872 if (len < slen) return -1;
4873 if (len - pos < slen) pos = len - slen;
4874 if (len == 0) return pos;
4875
4876 sbeg = RSTRING_PTR(str);
4877
4878 if (pos == 0) {
4879 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4880 return 0;
4881 else
4882 return -1;
4883 }
4884
4885 s = sbeg + pos;
4886 return str_rindex(str, sub, s, enc);
4887}
4888
4889/*
4890 * call-seq:
4891 * byterindex(object, offset = self.bytesize) -> integer or nil
4892 *
4893 * Returns the 0-based integer index of a substring of +self+
4894 * that is the _last_ match for the given +object+ (a string or Regexp) and +offset+,
4895 * or +nil+ if there is no such substring;
4896 * the returned index is the count of _bytes_ (not characters).
4897 *
4898 * When +object+ is a string,
4899 * returns the index of the _last_ found substring equal to +object+:
4900 *
4901 * s = 'foo' # => "foo"
4902 * s.size # => 3 # Three 1-byte characters.
4903 * s.bytesize # => 3 # Three bytes.
4904 * s.byterindex('f') # => 0
4905 s.byterindex('o') # => 2
4906 s.byterindex('oo') # => 1
4907 s.byterindex('ooo') # => nil
4908 *
4909 * When +object+ is a Regexp,
4910 * returns the index of the last found substring matching +object+;
4911 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
4912 *
4913 * s = 'foo'
4914 * s.byterindex(/f/) # => 0
4915 * $~ # => #<MatchData "f">
4916 * s.byterindex(/o/) # => 2
4917 * s.byterindex(/oo/) # => 1
4918 * s.byterindex(/ooo/) # => nil
4919 * $~ # => nil
4920 *
4921 * The last match means starting at the possible last position,
4922 * not the last of the longest matches:
4923 *
4924 * s = 'foo'
4925 * s.byterindex(/o+/) # => 2
4926 * $~ #=> #<MatchData "o">
4927 *
4928 * To get the last longest match, use a negative lookbehind:
4929 *
4930 * s = 'foo'
4931 * s.byterindex(/(?<!o)o+/) # => 1
4932 * $~ # => #<MatchData "oo">
4933 *
4934 * Or use method #byteindex with negative lookahead:
4935 *
4936 * s = 'foo'
4937 * s.byteindex(/o+(?!.*o)/) # => 1
4938 * $~ #=> #<MatchData "oo">
4939 *
4940 * \Integer argument +offset+, if given, specifies the 0-based index
4941 * of the byte where searching is to end.
4942 *
4943 * When +offset+ is non-negative,
4944 * searching ends at byte position +offset+:
4945 *
4946 * s = 'foo'
4947 * s.byterindex('o', 0) # => nil
4948 * s.byterindex('o', 1) # => 1
4949 * s.byterindex('o', 2) # => 2
4950 * s.byterindex('o', 3) # => 2
4951 *
4952 * When +offset+ is negative, counts backward from the end of +self+:
4953 *
4954 * s = 'foo'
4955 * s.byterindex('o', -1) # => 2
4956 * s.byterindex('o', -2) # => 1
4957 * s.byterindex('o', -3) # => nil
4958 *
4959 * Raises IndexError if the byte at +offset+ is not the first byte of a character:
4960 *
4961 * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
4962 * s.size # => 2 # Two 3-byte characters.
4963 * s.bytesize # => 6 # Six bytes.
4964 * s.byterindex("\uFFFF") # => 3
4965 * s.byterindex("\uFFFF", 1) # Raises IndexError
4966 * s.byterindex("\uFFFF", 2) # Raises IndexError
4967 * s.byterindex("\uFFFF", 3) # => 3
4968 * s.byterindex("\uFFFF", 4) # Raises IndexError
4969 * s.byterindex("\uFFFF", 5) # Raises IndexError
4970 * s.byterindex("\uFFFF", 6) # => nil
4971 *
4972 * Related: see {Querying}[rdoc-ref:String@Querying].
4973 */
4974
4975static VALUE
4976rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
4977{
4978 VALUE sub;
4979 VALUE initpos;
4980 long pos, len = RSTRING_LEN(str);
4981
4982 if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
4983 pos = NUM2LONG(initpos);
4984 if (pos < 0 && (pos += len) < 0) {
4985 if (RB_TYPE_P(sub, T_REGEXP)) {
4987 }
4988 return Qnil;
4989 }
4990 if (pos > len) pos = len;
4991 }
4992 else {
4993 pos = len;
4994 }
4995
4996 str_ensure_byte_pos(str, pos);
4997
4998 if (RB_TYPE_P(sub, T_REGEXP)) {
4999 if (rb_reg_search(sub, str, pos, 1) >= 0) {
5000 VALUE match = rb_backref_get();
5001 struct re_registers *regs = RMATCH_REGS(match);
5002 pos = BEG(0);
5003 return LONG2NUM(pos);
5004 }
5005 }
5006 else {
5007 StringValue(sub);
5008 pos = rb_str_byterindex(str, sub, pos);
5009 if (pos >= 0) return LONG2NUM(pos);
5010 }
5011 return Qnil;
5012}
5013
5014/*
5015 * call-seq:
5016 * self =~ object -> integer or nil
5017 *
5018 * When +object+ is a Regexp, returns the index of the first substring in +self+
5019 * matched by +object+,
5020 * or +nil+ if no match is found;
5021 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
5022 *
5023 * 'foo' =~ /f/ # => 0
5024 * $~ # => #<MatchData "f">
5025 * 'foo' =~ /o/ # => 1
5026 * $~ # => #<MatchData "o">
5027 * 'foo' =~ /x/ # => nil
5028 * $~ # => nil
5029 *
5030 * Note that <tt>string =~ regexp</tt> is different from <tt>regexp =~ string</tt>
5031 * (see Regexp#=~):
5032 *
5033 * number = nil
5034 * 'no. 9' =~ /(?<number>\d+)/ # => 4
5035 * number # => nil # Not assigned.
5036 * /(?<number>\d+)/ =~ 'no. 9' # => 4
5037 * number # => "9" # Assigned.
5038 *
5039 * If +object+ is not a Regexp, returns the value
5040 * returned by <tt>object =~ self</tt>.
5041 *
5042 * Related: see {Querying}[rdoc-ref:String@Querying].
5043 */
5044
5045static VALUE
5046rb_str_match(VALUE x, VALUE y)
5047{
5048 switch (OBJ_BUILTIN_TYPE(y)) {
5049 case T_STRING:
5050 rb_raise(rb_eTypeError, "type mismatch: String given");
5051
5052 case T_REGEXP:
5053 return rb_reg_match(y, x);
5054
5055 default:
5056 return rb_funcall(y, idEqTilde, 1, x);
5057 }
5058}
5059
5060
5061static VALUE get_pat(VALUE);
5062
5063
5064/*
5065 * call-seq:
5066 * match(pattern, offset = 0) -> matchdata or nil
5067 * match(pattern, offset = 0) {|matchdata| ... } -> object
5068 *
5069 * Creates a MatchData object based on +self+ and the given arguments;
5070 * updates {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5071 *
5072 * - Computes +regexp+ by converting +pattern+ (if not already a Regexp).
5073 *
5074 * regexp = Regexp.new(pattern)
5075 *
5076 * - Computes +matchdata+, which will be either a MatchData object or +nil+
5077 * (see Regexp#match):
5078 *
5079 * matchdata = regexp.match(self[offset..])
5080 *
5081 * With no block given, returns the computed +matchdata+ or +nil+:
5082 *
5083 * 'foo'.match('f') # => #<MatchData "f">
5084 * 'foo'.match('o') # => #<MatchData "o">
5085 * 'foo'.match('x') # => nil
5086 * 'foo'.match('f', 1) # => nil
5087 * 'foo'.match('o', 1) # => #<MatchData "o">
5088 *
5089 * With a block given and computed +matchdata+ non-nil, calls the block with +matchdata+;
5090 * returns the block's return value:
5091 *
5092 * 'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
5093 *
5094 * With a block given and +nil+ +matchdata+, does not call the block:
5095 *
5096 * 'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => nil
5097 *
5098 * Related: see {Querying}[rdoc-ref:String@Querying].
5099 */
5100
5101static VALUE
5102rb_str_match_m(int argc, VALUE *argv, VALUE str)
5103{
5104 VALUE re, result;
5105 if (argc < 1)
5106 rb_check_arity(argc, 1, 2);
5107 re = argv[0];
5108 argv[0] = str;
5109 result = rb_funcallv(get_pat(re), rb_intern("match"), argc, argv);
5110 if (!NIL_P(result) && rb_block_given_p()) {
5111 return rb_yield(result);
5112 }
5113 return result;
5114}
5115
5116/*
5117 * call-seq:
5118 * match?(pattern, offset = 0) -> true or false
5119 *
5120 * Returns whether a match is found for +self+ and the given arguments;
5121 * does not update {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
5122 *
5123 * Computes +regexp+ by converting +pattern+ (if not already a Regexp):
5124 *
5125 * regexp = Regexp.new(pattern)
5126 *
5127 * Returns +true+ if <tt>self[offset..].match(regexp)</tt> returns a MatchData object,
5128 * +false+ otherwise:
5129 *
5130 * 'foo'.match?(/o/) # => true
5131 * 'foo'.match?('o') # => true
5132 * 'foo'.match?(/x/) # => false
5133 * 'foo'.match?('f', 1) # => false
5134 * 'foo'.match?('o', 1) # => true
5135 *
5136 * Related: see {Querying}[rdoc-ref:String@Querying].
5137 */
5138
5139static VALUE
5140rb_str_match_m_p(int argc, VALUE *argv, VALUE str)
5141{
5142 VALUE re;
5143 rb_check_arity(argc, 1, 2);
5144 re = get_pat(argv[0]);
5145 return rb_reg_match_p(re, str, argc > 1 ? NUM2LONG(argv[1]) : 0);
5146}
5147
5148enum neighbor_char {
5149 NEIGHBOR_NOT_CHAR,
5150 NEIGHBOR_FOUND,
5151 NEIGHBOR_WRAPPED
5152};
5153
5154static enum neighbor_char
5155enc_succ_char(char *p, long len, rb_encoding *enc)
5156{
5157 long i;
5158 int l;
5159
5160 if (rb_enc_mbminlen(enc) > 1) {
5161 /* wchar, trivial case */
5162 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5163 if (!MBCLEN_CHARFOUND_P(r)) {
5164 return NEIGHBOR_NOT_CHAR;
5165 }
5166 c = rb_enc_mbc_to_codepoint(p, p + len, enc) + 1;
5167 l = rb_enc_code_to_mbclen(c, enc);
5168 if (!l) return NEIGHBOR_NOT_CHAR;
5169 if (l != len) return NEIGHBOR_WRAPPED;
5170 rb_enc_mbcput(c, p, enc);
5171 r = rb_enc_precise_mbclen(p, p + len, enc);
5172 if (!MBCLEN_CHARFOUND_P(r)) {
5173 return NEIGHBOR_NOT_CHAR;
5174 }
5175 return NEIGHBOR_FOUND;
5176 }
5177 while (1) {
5178 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0xff; i--)
5179 p[i] = '\0';
5180 if (i < 0)
5181 return NEIGHBOR_WRAPPED;
5182 ++((unsigned char*)p)[i];
5183 l = rb_enc_precise_mbclen(p, p+len, enc);
5184 if (MBCLEN_CHARFOUND_P(l)) {
5185 l = MBCLEN_CHARFOUND_LEN(l);
5186 if (l == len) {
5187 return NEIGHBOR_FOUND;
5188 }
5189 else {
5190 memset(p+l, 0xff, len-l);
5191 }
5192 }
5193 if (MBCLEN_INVALID_P(l) && i < len-1) {
5194 long len2;
5195 int l2;
5196 for (len2 = len-1; 0 < len2; len2--) {
5197 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5198 if (!MBCLEN_INVALID_P(l2))
5199 break;
5200 }
5201 memset(p+len2+1, 0xff, len-(len2+1));
5202 }
5203 }
5204}
5205
5206static enum neighbor_char
5207enc_pred_char(char *p, long len, rb_encoding *enc)
5208{
5209 long i;
5210 int l;
5211 if (rb_enc_mbminlen(enc) > 1) {
5212 /* wchar, trivial case */
5213 int r = rb_enc_precise_mbclen(p, p + len, enc), c;
5214 if (!MBCLEN_CHARFOUND_P(r)) {
5215 return NEIGHBOR_NOT_CHAR;
5216 }
5217 c = rb_enc_mbc_to_codepoint(p, p + len, enc);
5218 if (!c) return NEIGHBOR_NOT_CHAR;
5219 --c;
5220 l = rb_enc_code_to_mbclen(c, enc);
5221 if (!l) return NEIGHBOR_NOT_CHAR;
5222 if (l != len) return NEIGHBOR_WRAPPED;
5223 rb_enc_mbcput(c, p, enc);
5224 r = rb_enc_precise_mbclen(p, p + len, enc);
5225 if (!MBCLEN_CHARFOUND_P(r)) {
5226 return NEIGHBOR_NOT_CHAR;
5227 }
5228 return NEIGHBOR_FOUND;
5229 }
5230 while (1) {
5231 for (i = len-1; 0 <= i && (unsigned char)p[i] == 0; i--)
5232 p[i] = '\xff';
5233 if (i < 0)
5234 return NEIGHBOR_WRAPPED;
5235 --((unsigned char*)p)[i];
5236 l = rb_enc_precise_mbclen(p, p+len, enc);
5237 if (MBCLEN_CHARFOUND_P(l)) {
5238 l = MBCLEN_CHARFOUND_LEN(l);
5239 if (l == len) {
5240 return NEIGHBOR_FOUND;
5241 }
5242 else {
5243 memset(p+l, 0, len-l);
5244 }
5245 }
5246 if (MBCLEN_INVALID_P(l) && i < len-1) {
5247 long len2;
5248 int l2;
5249 for (len2 = len-1; 0 < len2; len2--) {
5250 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5251 if (!MBCLEN_INVALID_P(l2))
5252 break;
5253 }
5254 memset(p+len2+1, 0, len-(len2+1));
5255 }
5256 }
5257}
5258
5259/*
5260 overwrite +p+ by succeeding letter in +enc+ and returns
5261 NEIGHBOR_FOUND or NEIGHBOR_WRAPPED.
5262 When NEIGHBOR_WRAPPED, carried-out letter is stored into carry.
5263 assuming each ranges are successive, and mbclen
5264 never change in each ranges.
5265 NEIGHBOR_NOT_CHAR is returned if invalid character or the range has only one
5266 character.
5267 */
5268static enum neighbor_char
5269enc_succ_alnum_char(char *p, long len, rb_encoding *enc, char *carry)
5270{
5271 enum neighbor_char ret;
5272 unsigned int c;
5273 int ctype;
5274 int range;
5275 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5276
5277 /* skip 03A2, invalid char between GREEK CAPITAL LETTERS */
5278 int try;
5279 const int max_gaps = 1;
5280
5281 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5282 if (rb_enc_isctype(c, ONIGENC_CTYPE_DIGIT, enc))
5283 ctype = ONIGENC_CTYPE_DIGIT;
5284 else if (rb_enc_isctype(c, ONIGENC_CTYPE_ALPHA, enc))
5285 ctype = ONIGENC_CTYPE_ALPHA;
5286 else
5287 return NEIGHBOR_NOT_CHAR;
5288
5289 MEMCPY(save, p, char, len);
5290 for (try = 0; try <= max_gaps; ++try) {
5291 ret = enc_succ_char(p, len, enc);
5292 if (ret == NEIGHBOR_FOUND) {
5293 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5294 if (rb_enc_isctype(c, ctype, enc))
5295 return NEIGHBOR_FOUND;
5296 }
5297 }
5298 MEMCPY(p, save, char, len);
5299 range = 1;
5300 while (1) {
5301 MEMCPY(save, p, char, len);
5302 ret = enc_pred_char(p, len, enc);
5303 if (ret == NEIGHBOR_FOUND) {
5304 c = rb_enc_mbc_to_codepoint(p, p+len, enc);
5305 if (!rb_enc_isctype(c, ctype, enc)) {
5306 MEMCPY(p, save, char, len);
5307 break;
5308 }
5309 }
5310 else {
5311 MEMCPY(p, save, char, len);
5312 break;
5313 }
5314 range++;
5315 }
5316 if (range == 1) {
5317 return NEIGHBOR_NOT_CHAR;
5318 }
5319
5320 if (ctype != ONIGENC_CTYPE_DIGIT) {
5321 MEMCPY(carry, p, char, len);
5322 return NEIGHBOR_WRAPPED;
5323 }
5324
5325 MEMCPY(carry, p, char, len);
5326 enc_succ_char(carry, len, enc);
5327 return NEIGHBOR_WRAPPED;
5328}
5329
5330
5331static VALUE str_succ(VALUE str);
5332
5333/*
5334 * call-seq:
5335 * succ -> new_str
5336 *
5337 * :include: doc/string/succ.rdoc
5338 *
5339 */
5340
5341VALUE
5343{
5344 VALUE str;
5345 str = rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5346 rb_enc_cr_str_copy_for_substr(str, orig);
5347 return str_succ(str);
5348}
5349
5350static VALUE
5351str_succ(VALUE str)
5352{
5353 rb_encoding *enc;
5354 char *sbeg, *s, *e, *last_alnum = 0;
5355 int found_alnum = 0;
5356 long l, slen;
5357 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] = "\1";
5358 long carry_pos = 0, carry_len = 1;
5359 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5360
5361 slen = RSTRING_LEN(str);
5362 if (slen == 0) return str;
5363
5364 enc = STR_ENC_GET(str);
5365 sbeg = RSTRING_PTR(str);
5366 s = e = sbeg + slen;
5367
5368 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5369 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5370 if (ISALPHA(*last_alnum) ? ISDIGIT(*s) :
5371 ISDIGIT(*last_alnum) ? ISALPHA(*s) : 0) {
5372 break;
5373 }
5374 }
5375 l = rb_enc_precise_mbclen(s, e, enc);
5376 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5377 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5378 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5379 switch (neighbor) {
5380 case NEIGHBOR_NOT_CHAR:
5381 continue;
5382 case NEIGHBOR_FOUND:
5383 return str;
5384 case NEIGHBOR_WRAPPED:
5385 last_alnum = s;
5386 break;
5387 }
5388 found_alnum = 1;
5389 carry_pos = s - sbeg;
5390 carry_len = l;
5391 }
5392 if (!found_alnum) { /* str contains no alnum */
5393 s = e;
5394 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5395 enum neighbor_char neighbor;
5396 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5397 l = rb_enc_precise_mbclen(s, e, enc);
5398 if (!ONIGENC_MBCLEN_CHARFOUND_P(l)) continue;
5399 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5400 MEMCPY(tmp, s, char, l);
5401 neighbor = enc_succ_char(tmp, l, enc);
5402 switch (neighbor) {
5403 case NEIGHBOR_FOUND:
5404 MEMCPY(s, tmp, char, l);
5405 return str;
5406 break;
5407 case NEIGHBOR_WRAPPED:
5408 MEMCPY(s, tmp, char, l);
5409 break;
5410 case NEIGHBOR_NOT_CHAR:
5411 break;
5412 }
5413 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5414 /* wrapped to \0...\0. search next valid char. */
5415 enc_succ_char(s, l, enc);
5416 }
5417 if (!rb_enc_asciicompat(enc)) {
5418 MEMCPY(carry, s, char, l);
5419 carry_len = l;
5420 }
5421 carry_pos = s - sbeg;
5422 }
5424 }
5425 RESIZE_CAPA(str, slen + carry_len);
5426 sbeg = RSTRING_PTR(str);
5427 s = sbeg + carry_pos;
5428 memmove(s + carry_len, s, slen - carry_pos);
5429 memmove(s, carry, carry_len);
5430 slen += carry_len;
5431 STR_SET_LEN(str, slen);
5432 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5434 return str;
5435}
5436
5437
5438/*
5439 * call-seq:
5440 * succ! -> self
5441 *
5442 * Like String#succ, but modifies +self+ in place; returns +self+.
5443 *
5444 * Related: see {Modifying}[rdoc-ref:String@Modifying].
5445 */
5446
5447static VALUE
5448rb_str_succ_bang(VALUE str)
5449{
5450 rb_str_modify(str);
5451 str_succ(str);
5452 return str;
5453}
5454
5455static int
5456all_digits_p(const char *s, long len)
5457{
5458 while (len-- > 0) {
5459 if (!ISDIGIT(*s)) return 0;
5460 s++;
5461 }
5462 return 1;
5463}
5464
5465static int
5466str_upto_i(VALUE str, VALUE arg)
5467{
5468 rb_yield(str);
5469 return 0;
5470}
5471
5472/*
5473 * call-seq:
5474 * upto(other_string, exclusive = false) {|string| ... } -> self
5475 * upto(other_string, exclusive = false) -> new_enumerator
5476 *
5477 * :include: doc/string/upto.rdoc
5478 *
5479 */
5480
5481static VALUE
5482rb_str_upto(int argc, VALUE *argv, VALUE beg)
5483{
5484 VALUE end, exclusive;
5485
5486 rb_scan_args(argc, argv, "11", &end, &exclusive);
5487 RETURN_ENUMERATOR(beg, argc, argv);
5488 return rb_str_upto_each(beg, end, RTEST(exclusive), str_upto_i, Qnil);
5489}
5490
5491VALUE
5492rb_str_upto_each(VALUE beg, VALUE end, int excl, int (*each)(VALUE, VALUE), VALUE arg)
5493{
5494 VALUE current, after_end;
5495 ID succ;
5496 int n, ascii;
5497 rb_encoding *enc;
5498
5499 CONST_ID(succ, "succ");
5500 StringValue(end);
5501 enc = rb_enc_check(beg, end);
5502 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5503 /* single character */
5504 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5505 char c = RSTRING_PTR(beg)[0];
5506 char e = RSTRING_PTR(end)[0];
5507
5508 if (c > e || (excl && c == e)) return beg;
5509 for (;;) {
5510 VALUE str = rb_enc_str_new(&c, 1, enc);
5512 if ((*each)(str, arg)) break;
5513 if (!excl && c == e) break;
5514 c++;
5515 if (excl && c == e) break;
5516 }
5517 return beg;
5518 }
5519 /* both edges are all digits */
5520 if (ascii && ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
5521 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5522 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5523 VALUE b, e;
5524 int width;
5525
5526 width = RSTRING_LENINT(beg);
5527 b = rb_str_to_inum(beg, 10, FALSE);
5528 e = rb_str_to_inum(end, 10, FALSE);
5529 if (FIXNUM_P(b) && FIXNUM_P(e)) {
5530 long bi = FIX2LONG(b);
5531 long ei = FIX2LONG(e);
5532 rb_encoding *usascii = rb_usascii_encoding();
5533
5534 while (bi <= ei) {
5535 if (excl && bi == ei) break;
5536 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5537 bi++;
5538 }
5539 }
5540 else {
5541 ID op = excl ? '<' : idLE;
5542 VALUE args[2], fmt = rb_fstring_lit("%.*d");
5543
5544 args[0] = INT2FIX(width);
5545 while (rb_funcall(b, op, 1, e)) {
5546 args[1] = b;
5547 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5548 b = rb_funcallv(b, succ, 0, 0);
5549 }
5550 }
5551 return beg;
5552 }
5553 /* normal case */
5554 n = rb_str_cmp(beg, end);
5555 if (n > 0 || (excl && n == 0)) return beg;
5556
5557 after_end = rb_funcallv(end, succ, 0, 0);
5558 current = str_duplicate(rb_cString, beg);
5559 while (!rb_str_equal(current, after_end)) {
5560 VALUE next = Qnil;
5561 if (excl || !rb_str_equal(current, end))
5562 next = rb_funcallv(current, succ, 0, 0);
5563 if ((*each)(current, arg)) break;
5564 if (NIL_P(next)) break;
5565 current = next;
5566 StringValue(current);
5567 if (excl && rb_str_equal(current, end)) break;
5568 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5569 break;
5570 }
5571
5572 return beg;
5573}
5574
5575VALUE
5576rb_str_upto_endless_each(VALUE beg, int (*each)(VALUE, VALUE), VALUE arg)
5577{
5578 VALUE current;
5579 ID succ;
5580
5581 CONST_ID(succ, "succ");
5582 /* both edges are all digits */
5583 if (is_ascii_string(beg) && ISDIGIT(RSTRING_PTR(beg)[0]) &&
5584 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5585 VALUE b, args[2], fmt = rb_fstring_lit("%.*d");
5586 int width = RSTRING_LENINT(beg);
5587 b = rb_str_to_inum(beg, 10, FALSE);
5588 if (FIXNUM_P(b)) {
5589 long bi = FIX2LONG(b);
5590 rb_encoding *usascii = rb_usascii_encoding();
5591
5592 while (FIXABLE(bi)) {
5593 if ((*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg)) break;
5594 bi++;
5595 }
5596 b = LONG2NUM(bi);
5597 }
5598 args[0] = INT2FIX(width);
5599 while (1) {
5600 args[1] = b;
5601 if ((*each)(rb_str_format(numberof(args), args, fmt), arg)) break;
5602 b = rb_funcallv(b, succ, 0, 0);
5603 }
5604 }
5605 /* normal case */
5606 current = str_duplicate(rb_cString, beg);
5607 while (1) {
5608 VALUE next = rb_funcallv(current, succ, 0, 0);
5609 if ((*each)(current, arg)) break;
5610 current = next;
5611 StringValue(current);
5612 if (RSTRING_LEN(current) == 0)
5613 break;
5614 }
5615
5616 return beg;
5617}
5618
5619static int
5620include_range_i(VALUE str, VALUE arg)
5621{
5622 VALUE *argp = (VALUE *)arg;
5623 if (!rb_equal(str, *argp)) return 0;
5624 *argp = Qnil;
5625 return 1;
5626}
5627
5628VALUE
5629rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive)
5630{
5631 beg = rb_str_new_frozen(beg);
5632 StringValue(end);
5633 end = rb_str_new_frozen(end);
5634 if (NIL_P(val)) return Qfalse;
5635 val = rb_check_string_type(val);
5636 if (NIL_P(val)) return Qfalse;
5637 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5638 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5639 rb_enc_asciicompat(STR_ENC_GET(val))) {
5640 const char *bp = RSTRING_PTR(beg);
5641 const char *ep = RSTRING_PTR(end);
5642 const char *vp = RSTRING_PTR(val);
5643 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5644 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5645 return Qfalse;
5646 else {
5647 char b = *bp;
5648 char e = *ep;
5649 char v = *vp;
5650
5651 if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
5652 if (b <= v && v < e) return Qtrue;
5653 return RBOOL(!RTEST(exclusive) && b <= v && v == e);
5654 }
5655 }
5656 }
5657#if 0
5658 /* both edges are all digits */
5659 if (ISDIGIT(*bp) && ISDIGIT(*ep) &&
5660 all_digits_p(bp, RSTRING_LEN(beg)) &&
5661 all_digits_p(ep, RSTRING_LEN(end))) {
5662 /* TODO */
5663 }
5664#endif
5665 }
5666 rb_str_upto_each(beg, end, RTEST(exclusive), include_range_i, (VALUE)&val);
5667
5668 return RBOOL(NIL_P(val));
5669}
5670
5671static VALUE
5672rb_str_subpat(VALUE str, VALUE re, VALUE backref)
5673{
5674 if (rb_reg_search(re, str, 0, 0) >= 0) {
5675 VALUE match = rb_backref_get();
5676 int nth = rb_reg_backref_number(match, backref);
5677 return rb_reg_nth_match(nth, match);
5678 }
5679 return Qnil;
5680}
5681
5682static VALUE
5683rb_str_aref(VALUE str, VALUE indx)
5684{
5685 long idx;
5686
5687 if (FIXNUM_P(indx)) {
5688 idx = FIX2LONG(indx);
5689 }
5690 else if (RB_TYPE_P(indx, T_REGEXP)) {
5691 return rb_str_subpat(str, indx, INT2FIX(0));
5692 }
5693 else if (RB_TYPE_P(indx, T_STRING)) {
5694 if (rb_str_index(str, indx, 0) != -1)
5695 return str_duplicate(rb_cString, indx);
5696 return Qnil;
5697 }
5698 else {
5699 /* check if indx is Range */
5700 long beg, len = str_strlen(str, NULL);
5701 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
5702 case Qfalse:
5703 break;
5704 case Qnil:
5705 return Qnil;
5706 default:
5707 return rb_str_substr(str, beg, len);
5708 }
5709 idx = NUM2LONG(indx);
5710 }
5711
5712 return str_substr(str, idx, 1, FALSE);
5713}
5714
5715
5716/*
5717 * call-seq:
5718 * self[index] -> new_string or nil
5719 * self[start, length] -> new_string or nil
5720 * self[range] -> new_string or nil
5721 * self[regexp, capture = 0] -> new_string or nil
5722 * self[substring] -> new_string or nil
5723 *
5724 * :include: doc/string/aref.rdoc
5725 *
5726 */
5727
5728static VALUE
5729rb_str_aref_m(int argc, VALUE *argv, VALUE str)
5730{
5731 if (argc == 2) {
5732 if (RB_TYPE_P(argv[0], T_REGEXP)) {
5733 return rb_str_subpat(str, argv[0], argv[1]);
5734 }
5735 else {
5736 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5737 }
5738 }
5739 rb_check_arity(argc, 1, 2);
5740 return rb_str_aref(str, argv[0]);
5741}
5742
5743VALUE
5745{
5746 char *ptr = RSTRING_PTR(str);
5747 long olen = RSTRING_LEN(str), nlen;
5748
5749 str_modifiable(str);
5750 if (len > olen) len = olen;
5751 nlen = olen - len;
5752 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5753 char *oldptr = ptr;
5754 int fl = (int)(RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5755 STR_SET_EMBED(str);
5756 ptr = RSTRING(str)->as.embed.ary;
5757 memmove(ptr, oldptr + len, nlen);
5758 if (fl == STR_NOEMBED) xfree(oldptr);
5759 }
5760 else {
5761 if (!STR_SHARED_P(str)) {
5762 VALUE shared = heap_str_make_shared(rb_obj_class(str), str);
5763 rb_enc_cr_str_exact_copy(shared, str);
5764 OBJ_FREEZE(shared);
5765 }
5766 ptr = RSTRING(str)->as.heap.ptr += len;
5767 }
5768 STR_SET_LEN(str, nlen);
5769
5770 if (!SHARABLE_MIDDLE_SUBSTRING) {
5771 TERM_FILL(ptr + nlen, TERM_LEN(str));
5772 }
5774 return str;
5775}
5776
5777static void
5778rb_str_update_1(VALUE str, long beg, long len, VALUE val, long vbeg, long vlen)
5779{
5780 char *sptr;
5781 long slen;
5782 int cr;
5783
5784 if (beg == 0 && vlen == 0) {
5785 rb_str_drop_bytes(str, len);
5786 return;
5787 }
5788
5789 str_modify_keep_cr(str);
5790 RSTRING_GETMEM(str, sptr, slen);
5791 if (len < vlen) {
5792 /* expand string */
5793 RESIZE_CAPA(str, slen + vlen - len);
5794 sptr = RSTRING_PTR(str);
5795 }
5796
5798 cr = rb_enc_str_coderange(val);
5799 else
5801
5802 if (vlen != len) {
5803 memmove(sptr + beg + vlen,
5804 sptr + beg + len,
5805 slen - (beg + len));
5806 }
5807 if (vlen < beg && len < 0) {
5808 MEMZERO(sptr + slen, char, -len);
5809 }
5810 if (vlen > 0) {
5811 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5812 }
5813 slen += vlen - len;
5814 STR_SET_LEN(str, slen);
5815 TERM_FILL(&sptr[slen], TERM_LEN(str));
5816 ENC_CODERANGE_SET(str, cr);
5817}
5818
5819static inline void
5820rb_str_update_0(VALUE str, long beg, long len, VALUE val)
5821{
5822 rb_str_update_1(str, beg, len, val, 0, RSTRING_LEN(val));
5823}
5824
5825void
5826rb_str_update(VALUE str, long beg, long len, VALUE val)
5827{
5828 long slen;
5829 char *p, *e;
5830 rb_encoding *enc;
5831 int singlebyte = single_byte_optimizable(str);
5832 int cr;
5833
5834 if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
5835
5836 StringValue(val);
5837 enc = rb_enc_check(str, val);
5838 slen = str_strlen(str, enc); /* rb_enc_check */
5839
5840 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5841 rb_raise(rb_eIndexError, "index %ld out of string", beg);
5842 }
5843 if (beg < 0) {
5844 beg += slen;
5845 }
5846 RUBY_ASSERT(beg >= 0);
5847 RUBY_ASSERT(beg <= slen);
5848
5849 if (len > slen - beg) {
5850 len = slen - beg;
5851 }
5852 p = str_nth(RSTRING_PTR(str), RSTRING_END(str), beg, enc, singlebyte);
5853 if (!p) p = RSTRING_END(str);
5854 e = str_nth(p, RSTRING_END(str), len, enc, singlebyte);
5855 if (!e) e = RSTRING_END(str);
5856 /* error check */
5857 beg = p - RSTRING_PTR(str); /* physical position */
5858 len = e - p; /* physical length */
5859 rb_str_update_0(str, beg, len, val);
5860 rb_enc_associate(str, enc);
5862 if (cr != ENC_CODERANGE_BROKEN)
5863 ENC_CODERANGE_SET(str, cr);
5864}
5865
5866static void
5867rb_str_subpat_set(VALUE str, VALUE re, VALUE backref, VALUE val)
5868{
5869 int nth;
5870 VALUE match;
5871 long start, end, len;
5872 rb_encoding *enc;
5873 struct re_registers *regs;
5874
5875 if (rb_reg_search(re, str, 0, 0) < 0) {
5876 rb_raise(rb_eIndexError, "regexp not matched");
5877 }
5878 match = rb_backref_get();
5879 nth = rb_reg_backref_number(match, backref);
5880 regs = RMATCH_REGS(match);
5881 if ((nth >= regs->num_regs) || ((nth < 0) && (-nth >= regs->num_regs))) {
5882 rb_raise(rb_eIndexError, "index %d out of regexp", nth);
5883 }
5884 if (nth < 0) {
5885 nth += regs->num_regs;
5886 }
5887
5888 start = BEG(nth);
5889 if (start == -1) {
5890 rb_raise(rb_eIndexError, "regexp group %d not matched", nth);
5891 }
5892 end = END(nth);
5893 len = end - start;
5894 StringValue(val);
5895 enc = rb_enc_check_str(str, val);
5896 rb_str_update_0(str, start, len, val);
5897 rb_enc_associate(str, enc);
5898}
5899
5900static VALUE
5901rb_str_aset(VALUE str, VALUE indx, VALUE val)
5902{
5903 long idx, beg;
5904
5905 switch (TYPE(indx)) {
5906 case T_REGEXP:
5907 rb_str_subpat_set(str, indx, INT2FIX(0), val);
5908 return val;
5909
5910 case T_STRING:
5911 beg = rb_str_index(str, indx, 0);
5912 if (beg < 0) {
5913 rb_raise(rb_eIndexError, "string not matched");
5914 }
5915 beg = rb_str_sublen(str, beg);
5916 rb_str_update(str, beg, str_strlen(indx, NULL), val);
5917 return val;
5918
5919 default:
5920 /* check if indx is Range */
5921 {
5922 long beg, len;
5923 if (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 2)) {
5924 rb_str_update(str, beg, len, val);
5925 return val;
5926 }
5927 }
5928 /* FALLTHROUGH */
5929
5930 case T_FIXNUM:
5931 idx = NUM2LONG(indx);
5932 rb_str_update(str, idx, 1, val);
5933 return val;
5934 }
5935}
5936
5937/*
5938 * call-seq:
5939 * self[index] = other_string -> new_string
5940 * self[start, length] = other_string -> new_string
5941 * self[range] = other_string -> new_string
5942 * self[regexp, capture = 0] = other_string -> new_string
5943 * self[substring] = other_string -> new_string
5944 *
5945 * :include: doc/string/aset.rdoc
5946 *
5947 */
5948
5949static VALUE
5950rb_str_aset_m(int argc, VALUE *argv, VALUE str)
5951{
5952 if (argc == 3) {
5953 if (RB_TYPE_P(argv[0], T_REGEXP)) {
5954 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
5955 }
5956 else {
5957 rb_str_update(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
5958 }
5959 return argv[2];
5960 }
5961 rb_check_arity(argc, 2, 3);
5962 return rb_str_aset(str, argv[0], argv[1]);
5963}
5964
5965/*
5966 * call-seq:
5967 * insert(offset, other_string) -> self
5968 *
5969 * :include: doc/string/insert.rdoc
5970 *
5971 */
5972
5973static VALUE
5974rb_str_insert(VALUE str, VALUE idx, VALUE str2)
5975{
5976 long pos = NUM2LONG(idx);
5977
5978 if (pos == -1) {
5979 return rb_str_append(str, str2);
5980 }
5981 else if (pos < 0) {
5982 pos++;
5983 }
5984 rb_str_update(str, pos, 0, str2);
5985 return str;
5986}
5987
5988
5989/*
5990 * call-seq:
5991 * slice!(index) -> new_string or nil
5992 * slice!(start, length) -> new_string or nil
5993 * slice!(range) -> new_string or nil
5994 * slice!(regexp, capture = 0) -> new_string or nil
5995 * slice!(substring) -> new_string or nil
5996 *
5997 * Like String#[] (and its alias String#slice), except that:
5998 *
5999 * - Performs substitutions in +self+ (not in a copy of +self+).
6000 * - Returns the removed substring if any modifications were made, +nil+ otherwise.
6001 *
6002 * A few examples:
6003 *
6004 * s = 'hello'
6005 * s.slice!('e') # => "e"
6006 * s # => "hllo"
6007 * s.slice!('e') # => nil
6008 * s # => "hllo"
6009 *
6010 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6011 */
6012
6013static VALUE
6014rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
6015{
6016 VALUE result = Qnil;
6017 VALUE indx;
6018 long beg, len = 1;
6019 char *p;
6020
6021 rb_check_arity(argc, 1, 2);
6022 str_modify_keep_cr(str);
6023 indx = argv[0];
6024 if (RB_TYPE_P(indx, T_REGEXP)) {
6025 if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
6026 VALUE match = rb_backref_get();
6027 struct re_registers *regs = RMATCH_REGS(match);
6028 int nth = 0;
6029 if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
6030 if ((nth += regs->num_regs) <= 0) return Qnil;
6031 }
6032 else if (nth >= regs->num_regs) return Qnil;
6033 beg = BEG(nth);
6034 len = END(nth) - beg;
6035 goto subseq;
6036 }
6037 else if (argc == 2) {
6038 beg = NUM2LONG(indx);
6039 len = NUM2LONG(argv[1]);
6040 goto num_index;
6041 }
6042 else if (FIXNUM_P(indx)) {
6043 beg = FIX2LONG(indx);
6044 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6045 if (!len) return Qnil;
6046 beg = p - RSTRING_PTR(str);
6047 goto subseq;
6048 }
6049 else if (RB_TYPE_P(indx, T_STRING)) {
6050 beg = rb_str_index(str, indx, 0);
6051 if (beg == -1) return Qnil;
6052 len = RSTRING_LEN(indx);
6053 result = str_duplicate(rb_cString, indx);
6054 goto squash;
6055 }
6056 else {
6057 switch (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 0)) {
6058 case Qnil:
6059 return Qnil;
6060 case Qfalse:
6061 beg = NUM2LONG(indx);
6062 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6063 if (!len) return Qnil;
6064 beg = p - RSTRING_PTR(str);
6065 goto subseq;
6066 default:
6067 goto num_index;
6068 }
6069 }
6070
6071 num_index:
6072 if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
6073 beg = p - RSTRING_PTR(str);
6074
6075 subseq:
6076 result = rb_str_new(RSTRING_PTR(str)+beg, len);
6077 rb_enc_cr_str_copy_for_substr(result, str);
6078
6079 squash:
6080 if (len > 0) {
6081 if (beg == 0) {
6082 rb_str_drop_bytes(str, len);
6083 }
6084 else {
6085 char *sptr = RSTRING_PTR(str);
6086 long slen = RSTRING_LEN(str);
6087 if (beg + len > slen) /* pathological check */
6088 len = slen - beg;
6089 memmove(sptr + beg,
6090 sptr + beg + len,
6091 slen - (beg + len));
6092 slen -= len;
6093 STR_SET_LEN(str, slen);
6094 TERM_FILL(&sptr[slen], TERM_LEN(str));
6095 }
6096 }
6097 return result;
6098}
6099
6100static VALUE
6101get_pat(VALUE pat)
6102{
6103 VALUE val;
6104
6105 switch (OBJ_BUILTIN_TYPE(pat)) {
6106 case T_REGEXP:
6107 return pat;
6108
6109 case T_STRING:
6110 break;
6111
6112 default:
6113 val = rb_check_string_type(pat);
6114 if (NIL_P(val)) {
6115 Check_Type(pat, T_REGEXP);
6116 }
6117 pat = val;
6118 }
6119
6120 return rb_reg_regcomp(pat);
6121}
6122
6123static VALUE
6124get_pat_quoted(VALUE pat, int check)
6125{
6126 VALUE val;
6127
6128 switch (OBJ_BUILTIN_TYPE(pat)) {
6129 case T_REGEXP:
6130 return pat;
6131
6132 case T_STRING:
6133 break;
6134
6135 default:
6136 val = rb_check_string_type(pat);
6137 if (NIL_P(val)) {
6138 Check_Type(pat, T_REGEXP);
6139 }
6140 pat = val;
6141 }
6142 if (check && is_broken_string(pat)) {
6143 rb_exc_raise(rb_reg_check_preprocess(pat));
6144 }
6145 return pat;
6146}
6147
6148static long
6149rb_pat_search0(VALUE pat, VALUE str, long pos, int set_backref_str, VALUE *match)
6150{
6151 if (BUILTIN_TYPE(pat) == T_STRING) {
6152 pos = rb_str_byteindex(str, pat, pos);
6153 if (set_backref_str) {
6154 if (pos >= 0) {
6155 str = rb_str_new_frozen_String(str);
6156 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6157 if (match) {
6158 *match = match_data;
6159 }
6160 }
6161 else {
6163 }
6164 }
6165 return pos;
6166 }
6167 else {
6168 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6169 }
6170}
6171
6172static long
6173rb_pat_search(VALUE pat, VALUE str, long pos, int set_backref_str)
6174{
6175 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6176}
6177
6178
6179/*
6180 * call-seq:
6181 * sub!(pattern, replacement) -> self or nil
6182 * sub!(pattern) {|match| ... } -> self or nil
6183 *
6184 * Like String#sub, except that:
6185 *
6186 * - Changes are made to +self+, not to copy of +self+.
6187 * - Returns +self+ if any changes are made, +nil+ otherwise.
6188 *
6189 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6190 */
6191
6192static VALUE
6193rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
6194{
6195 VALUE pat, repl, hash = Qnil;
6196 int iter = 0;
6197 long plen;
6198 int min_arity = rb_block_given_p() ? 1 : 2;
6199 long beg;
6200
6201 rb_check_arity(argc, min_arity, 2);
6202 if (argc == 1) {
6203 iter = 1;
6204 }
6205 else {
6206 repl = argv[1];
6207 hash = rb_check_hash_type(argv[1]);
6208 if (NIL_P(hash)) {
6209 StringValue(repl);
6210 }
6211 }
6212
6213 pat = get_pat_quoted(argv[0], 1);
6214
6215 str_modifiable(str);
6216 beg = rb_pat_search(pat, str, 0, 1);
6217 if (beg >= 0) {
6218 rb_encoding *enc;
6219 int cr = ENC_CODERANGE(str);
6220 long beg0, end0;
6221 VALUE match, match0 = Qnil;
6222 struct re_registers *regs;
6223 char *p, *rp;
6224 long len, rlen;
6225
6226 match = rb_backref_get();
6227 regs = RMATCH_REGS(match);
6228 if (RB_TYPE_P(pat, T_STRING)) {
6229 beg0 = beg;
6230 end0 = beg0 + RSTRING_LEN(pat);
6231 match0 = pat;
6232 }
6233 else {
6234 beg0 = BEG(0);
6235 end0 = END(0);
6236 if (iter) match0 = rb_reg_nth_match(0, match);
6237 }
6238
6239 if (iter || !NIL_P(hash)) {
6240 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6241
6242 if (iter) {
6243 repl = rb_obj_as_string(rb_yield(match0));
6244 }
6245 else {
6246 repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0));
6247 repl = rb_obj_as_string(repl);
6248 }
6249 str_mod_check(str, p, len);
6250 rb_check_frozen(str);
6251 }
6252 else {
6253 repl = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
6254 }
6255
6256 enc = rb_enc_compatible(str, repl);
6257 if (!enc) {
6258 rb_encoding *str_enc = STR_ENC_GET(str);
6259 p = RSTRING_PTR(str); len = RSTRING_LEN(str);
6260 if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
6261 coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
6262 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
6263 rb_enc_inspect_name(str_enc),
6264 rb_enc_inspect_name(STR_ENC_GET(repl)));
6265 }
6266 enc = STR_ENC_GET(repl);
6267 }
6268 rb_str_modify(str);
6269 rb_enc_associate(str, enc);
6271 int cr2 = ENC_CODERANGE(repl);
6272 if (cr2 == ENC_CODERANGE_BROKEN ||
6273 (cr == ENC_CODERANGE_VALID && cr2 == ENC_CODERANGE_7BIT))
6275 else
6276 cr = cr2;
6277 }
6278 plen = end0 - beg0;
6279 rlen = RSTRING_LEN(repl);
6280 len = RSTRING_LEN(str);
6281 if (rlen > plen) {
6282 RESIZE_CAPA(str, len + rlen - plen);
6283 }
6284 p = RSTRING_PTR(str);
6285 if (rlen != plen) {
6286 memmove(p + beg0 + rlen, p + beg0 + plen, len - beg0 - plen);
6287 }
6288 rp = RSTRING_PTR(repl);
6289 memmove(p + beg0, rp, rlen);
6290 len += rlen - plen;
6291 STR_SET_LEN(str, len);
6292 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
6293 ENC_CODERANGE_SET(str, cr);
6294
6295 RB_GC_GUARD(match);
6296
6297 return str;
6298 }
6299 return Qnil;
6300}
6301
6302
6303/*
6304 * call-seq:
6305 * sub(pattern, replacement) -> new_string
6306 * sub(pattern) {|match| ... } -> new_string
6307 *
6308 * :include: doc/string/sub.rdoc
6309 */
6310
6311static VALUE
6312rb_str_sub(int argc, VALUE *argv, VALUE str)
6313{
6314 str = str_duplicate(rb_cString, str);
6315 rb_str_sub_bang(argc, argv, str);
6316 return str;
6317}
6318
6319static VALUE
6320str_gsub(int argc, VALUE *argv, VALUE str, int bang)
6321{
6322 VALUE pat, val = Qnil, repl, match0 = Qnil, dest, hash = Qnil, match = Qnil;
6323 long beg, beg0, end0;
6324 long offset, blen, slen, len, last;
6325 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6326 char *sp, *cp;
6327 int need_backref_str = -1;
6328 rb_encoding *str_enc;
6329
6330 switch (argc) {
6331 case 1:
6332 RETURN_ENUMERATOR(str, argc, argv);
6333 mode = ITER;
6334 break;
6335 case 2:
6336 repl = argv[1];
6337 hash = rb_check_hash_type(argv[1]);
6338 if (NIL_P(hash)) {
6339 StringValue(repl);
6340 }
6341 else if (rb_hash_default_unredefined(hash) && !FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6342 mode = FAST_MAP;
6343 }
6344 else {
6345 mode = MAP;
6346 }
6347 break;
6348 default:
6349 rb_error_arity(argc, 1, 2);
6350 }
6351
6352 pat = get_pat_quoted(argv[0], 1);
6353 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6354
6355 if (beg < 0) {
6356 if (bang) return Qnil; /* no match, no substitution */
6357 return str_duplicate(rb_cString, str);
6358 }
6359
6360 offset = 0;
6361 blen = RSTRING_LEN(str) + 30; /* len + margin */
6362 dest = rb_str_buf_new(blen);
6363 sp = RSTRING_PTR(str);
6364 slen = RSTRING_LEN(str);
6365 cp = sp;
6366 str_enc = STR_ENC_GET(str);
6367 rb_enc_associate(dest, str_enc);
6368 ENC_CODERANGE_SET(dest, rb_enc_asciicompat(str_enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
6369
6370 do {
6371 struct re_registers *regs = RMATCH_REGS(match);
6372 if (RB_TYPE_P(pat, T_STRING)) {
6373 beg0 = beg;
6374 end0 = beg0 + RSTRING_LEN(pat);
6375 match0 = pat;
6376 }
6377 else {
6378 beg0 = BEG(0);
6379 end0 = END(0);
6380 if (mode == ITER) match0 = rb_reg_nth_match(0, match);
6381 }
6382
6383 if (mode != STR) {
6384 if (mode == ITER) {
6385 val = rb_obj_as_string(rb_yield(match0));
6386 }
6387 else {
6388 struct RString fake_str = {RBASIC_INIT};
6389 VALUE key;
6390 if (mode == FAST_MAP) {
6391 // It is safe to use a fake_str here because we established that it won't escape,
6392 // as it's only used for `rb_hash_aref` and we checked the hash doesn't have a
6393 // default proc.
6394 key = setup_fake_str(&fake_str, sp + beg0, end0 - beg0, ENCODING_GET_INLINED(str));
6395 }
6396 else {
6397 key = rb_str_subseq(str, beg0, end0 - beg0);
6398 }
6399 val = rb_hash_aref(hash, key);
6400 val = rb_obj_as_string(val);
6401 }
6402 str_mod_check(str, sp, slen);
6403 if (val == dest) { /* paranoid check [ruby-dev:24827] */
6404 rb_raise(rb_eRuntimeError, "block should not cheat");
6405 }
6406 }
6407 else if (need_backref_str) {
6408 val = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
6409 if (need_backref_str < 0) {
6410 need_backref_str = val != repl;
6411 }
6412 }
6413 else {
6414 val = repl;
6415 }
6416
6417 len = beg0 - offset; /* copy pre-match substr */
6418 if (len) {
6419 rb_enc_str_buf_cat(dest, cp, len, str_enc);
6420 }
6421
6422 rb_str_buf_append(dest, val);
6423
6424 last = offset;
6425 offset = end0;
6426 if (beg0 == end0) {
6427 /*
6428 * Always consume at least one character of the input string
6429 * in order to prevent infinite loops.
6430 */
6431 if (RSTRING_LEN(str) <= end0) break;
6432 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0, RSTRING_END(str), str_enc);
6433 rb_enc_str_buf_cat(dest, RSTRING_PTR(str)+end0, len, str_enc);
6434 offset = end0 + len;
6435 }
6436 cp = RSTRING_PTR(str) + offset;
6437 if (offset > RSTRING_LEN(str)) break;
6438
6439 // In FAST_MAP and STR mode the backref can't escape so we can re-use the MatchData safely.
6440 if (mode != FAST_MAP && mode != STR) {
6441 match = Qnil;
6442 }
6443 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6444
6445 RB_GC_GUARD(match);
6446 } while (beg >= 0);
6447
6448 if (RSTRING_LEN(str) > offset) {
6449 rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
6450 }
6451 rb_pat_search0(pat, str, last, 1, &match);
6452 if (bang) {
6453 str_shared_replace(str, dest);
6454 }
6455 else {
6456 str = dest;
6457 }
6458
6459 return str;
6460}
6461
6462
6463/*
6464 * call-seq:
6465 * gsub!(pattern, replacement) -> self or nil
6466 * gsub!(pattern) {|match| ... } -> self or nil
6467 * gsub!(pattern) -> an_enumerator
6468 *
6469 * Like String#gsub, except that:
6470 *
6471 * - Performs substitutions in +self+ (not in a copy of +self+).
6472 * - Returns +self+ if any characters are removed, +nil+ otherwise.
6473 *
6474 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6475 */
6476
6477static VALUE
6478rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
6479{
6480 str_modify_keep_cr(str);
6481 return str_gsub(argc, argv, str, 1);
6482}
6483
6484
6485/*
6486 * call-seq:
6487 * gsub(pattern, replacement) -> new_string
6488 * gsub(pattern) {|match| ... } -> new_string
6489 * gsub(pattern) -> enumerator
6490 *
6491 * Returns a copy of +self+ with zero or more substrings replaced.
6492 *
6493 * Argument +pattern+ may be a string or a Regexp;
6494 * argument +replacement+ may be a string or a Hash.
6495 * Varying types for the argument values makes this method very versatile.
6496 *
6497 * Below are some simple examples;
6498 * for many more examples, see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
6499 *
6500 * With arguments +pattern+ and string +replacement+ given,
6501 * replaces each matching substring with the given +replacement+ string:
6502 *
6503 * s = 'abracadabra'
6504 * s.gsub('ab', 'AB') # => "ABracadABra"
6505 * s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
6506 *
6507 * With arguments +pattern+ and hash +replacement+ given,
6508 * replaces each matching substring with a value from the given +replacement+ hash,
6509 * or removes it:
6510 *
6511 * h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
6512 * s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
6513 * s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
6514 *
6515 * With argument +pattern+ and a block given,
6516 * calls the block with each matching substring;
6517 * replaces that substring with the block's return value:
6518 *
6519 * s.gsub(/[a-d]/) {|substring| substring.upcase }
6520 * # => "ABrACADABrA"
6521 *
6522 * With argument +pattern+ and no block given,
6523 * returns a new Enumerator.
6524 *
6525 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
6526 */
6527
6528static VALUE
6529rb_str_gsub(int argc, VALUE *argv, VALUE str)
6530{
6531 return str_gsub(argc, argv, str, 0);
6532}
6533
6534
6535/*
6536 * call-seq:
6537 * replace(other_string) -> self
6538 *
6539 * Replaces the contents of +self+ with the contents of +other_string+;
6540 * returns +self+:
6541 *
6542 * s = 'foo' # => "foo"
6543 * s.replace('bar') # => "bar"
6544 *
6545 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6546 */
6547
6548VALUE
6550{
6551 str_modifiable(str);
6552 if (str == str2) return str;
6553
6554 StringValue(str2);
6555 str_discard(str);
6556 return str_replace(str, str2);
6557}
6558
6559/*
6560 * call-seq:
6561 * clear -> self
6562 *
6563 * Removes the contents of +self+:
6564 *
6565 * s = 'foo'
6566 * s.clear # => ""
6567 * s # => ""
6568 *
6569 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6570 */
6571
6572static VALUE
6573rb_str_clear(VALUE str)
6574{
6575 str_discard(str);
6576 STR_SET_EMBED(str);
6577 STR_SET_LEN(str, 0);
6578 RSTRING_PTR(str)[0] = 0;
6579 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6581 else
6583 return str;
6584}
6585
6586/*
6587 * call-seq:
6588 * chr -> string
6589 *
6590 * :include: doc/string/chr.rdoc
6591 *
6592 */
6593
6594static VALUE
6595rb_str_chr(VALUE str)
6596{
6597 return rb_str_substr(str, 0, 1);
6598}
6599
6600/*
6601 * call-seq:
6602 * getbyte(index) -> integer or nil
6603 *
6604 * :include: doc/string/getbyte.rdoc
6605 *
6606 */
6607VALUE
6608rb_str_getbyte(VALUE str, VALUE index)
6609{
6610 long pos = NUM2LONG(index);
6611
6612 if (pos < 0)
6613 pos += RSTRING_LEN(str);
6614 if (pos < 0 || RSTRING_LEN(str) <= pos)
6615 return Qnil;
6616
6617 return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
6618}
6619
6620/*
6621 * call-seq:
6622 * setbyte(index, integer) -> integer
6623 *
6624 * Sets the byte at zero-based offset +index+ to the value of the given +integer+;
6625 * returns +integer+:
6626 *
6627 * s = 'xyzzy'
6628 * s.setbyte(2, 129) # => 129
6629 * s # => "xy\x81zy"
6630 *
6631 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6632 */
6633VALUE
6634rb_str_setbyte(VALUE str, VALUE index, VALUE value)
6635{
6636 long pos = NUM2LONG(index);
6637 long len = RSTRING_LEN(str);
6638 char *ptr, *head, *left = 0;
6639 rb_encoding *enc;
6640 int cr = ENC_CODERANGE_UNKNOWN, width, nlen;
6641
6642 if (pos < -len || len <= pos)
6643 rb_raise(rb_eIndexError, "index %ld out of string", pos);
6644 if (pos < 0)
6645 pos += len;
6646
6647 VALUE v = rb_to_int(value);
6648 VALUE w = rb_int_and(v, INT2FIX(0xff));
6649 char byte = (char)(NUM2INT(w) & 0xFF);
6650
6651 if (!str_independent(str))
6652 str_make_independent(str);
6653 enc = STR_ENC_GET(str);
6654 head = RSTRING_PTR(str);
6655 ptr = &head[pos];
6656 if (!STR_EMBED_P(str)) {
6657 cr = ENC_CODERANGE(str);
6658 switch (cr) {
6659 case ENC_CODERANGE_7BIT:
6660 left = ptr;
6661 *ptr = byte;
6662 if (ISASCII(byte)) goto end;
6663 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6664 if (!MBCLEN_CHARFOUND_P(nlen))
6666 else
6668 goto end;
6670 left = rb_enc_left_char_head(head, ptr, head+len, enc);
6671 width = rb_enc_precise_mbclen(left, head+len, enc);
6672 *ptr = byte;
6673 nlen = rb_enc_precise_mbclen(left, head+len, enc);
6674 if (!MBCLEN_CHARFOUND_P(nlen))
6676 else if (MBCLEN_CHARFOUND_LEN(nlen) != width || ISASCII(byte))
6678 goto end;
6679 }
6680 }
6682 *ptr = byte;
6683
6684 end:
6685 return value;
6686}
6687
6688static VALUE
6689str_byte_substr(VALUE str, long beg, long len, int empty)
6690{
6691 long n = RSTRING_LEN(str);
6692
6693 if (beg > n || len < 0) return Qnil;
6694 if (beg < 0) {
6695 beg += n;
6696 if (beg < 0) return Qnil;
6697 }
6698 if (len > n - beg)
6699 len = n - beg;
6700 if (len <= 0) {
6701 if (!empty) return Qnil;
6702 len = 0;
6703 }
6704
6705 VALUE str2 = str_subseq(str, beg, len);
6706
6707 str_enc_copy_direct(str2, str);
6708
6709 if (RSTRING_LEN(str2) == 0) {
6710 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
6712 else
6714 }
6715 else {
6716 switch (ENC_CODERANGE(str)) {
6717 case ENC_CODERANGE_7BIT:
6719 break;
6720 default:
6722 break;
6723 }
6724 }
6725
6726 return str2;
6727}
6728
6729VALUE
6730rb_str_byte_substr(VALUE str, VALUE beg, VALUE len)
6731{
6732 return str_byte_substr(str, NUM2LONG(beg), NUM2LONG(len), TRUE);
6733}
6734
6735static VALUE
6736str_byte_aref(VALUE str, VALUE indx)
6737{
6738 long idx;
6739 if (FIXNUM_P(indx)) {
6740 idx = FIX2LONG(indx);
6741 }
6742 else {
6743 /* check if indx is Range */
6744 long beg, len = RSTRING_LEN(str);
6745
6746 switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
6747 case Qfalse:
6748 break;
6749 case Qnil:
6750 return Qnil;
6751 default:
6752 return str_byte_substr(str, beg, len, TRUE);
6753 }
6754
6755 idx = NUM2LONG(indx);
6756 }
6757 return str_byte_substr(str, idx, 1, FALSE);
6758}
6759
6760/*
6761 * call-seq:
6762 * byteslice(offset, length = 1) -> string or nil
6763 * byteslice(range) -> string or nil
6764 *
6765 * :include: doc/string/byteslice.rdoc
6766 */
6767
6768static VALUE
6769rb_str_byteslice(int argc, VALUE *argv, VALUE str)
6770{
6771 if (argc == 2) {
6772 long beg = NUM2LONG(argv[0]);
6773 long len = NUM2LONG(argv[1]);
6774 return str_byte_substr(str, beg, len, TRUE);
6775 }
6776 rb_check_arity(argc, 1, 2);
6777 return str_byte_aref(str, argv[0]);
6778}
6779
6780static void
6781str_check_beg_len(VALUE str, long *beg, long *len)
6782{
6783 long end, slen = RSTRING_LEN(str);
6784
6785 if (*len < 0) rb_raise(rb_eIndexError, "negative length %ld", *len);
6786 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
6787 rb_raise(rb_eIndexError, "index %ld out of string", *beg);
6788 }
6789 if (*beg < 0) {
6790 *beg += slen;
6791 }
6792 RUBY_ASSERT(*beg >= 0);
6793 RUBY_ASSERT(*beg <= slen);
6794
6795 if (*len > slen - *beg) {
6796 *len = slen - *beg;
6797 }
6798 end = *beg + *len;
6799 str_ensure_byte_pos(str, *beg);
6800 str_ensure_byte_pos(str, end);
6801}
6802
6803/*
6804 * call-seq:
6805 * bytesplice(offset, length, str) -> self
6806 * bytesplice(offset, length, str, str_offset, str_length) -> self
6807 * bytesplice(range, str) -> self
6808 * bytesplice(range, str, str_range) -> self
6809 *
6810 * :include: doc/string/bytesplice.rdoc
6811 */
6812
6813static VALUE
6814rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
6815{
6816 long beg, len, vbeg, vlen;
6817 VALUE val;
6818 int cr;
6819
6820 rb_check_arity(argc, 2, 5);
6821 if (!(argc == 2 || argc == 3 || argc == 5)) {
6822 rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
6823 }
6824 if (argc == 2 || (argc == 3 && !RB_INTEGER_TYPE_P(argv[0]))) {
6825 if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
6826 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
6827 rb_builtin_class_name(argv[0]));
6828 }
6829 val = argv[1];
6830 StringValue(val);
6831 if (argc == 2) {
6832 /* bytesplice(range, str) */
6833 vbeg = 0;
6834 vlen = RSTRING_LEN(val);
6835 }
6836 else {
6837 /* bytesplice(range, str, str_range) */
6838 if (!rb_range_beg_len(argv[2], &vbeg, &vlen, RSTRING_LEN(val), 2)) {
6839 rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
6840 rb_builtin_class_name(argv[2]));
6841 }
6842 }
6843 }
6844 else {
6845 beg = NUM2LONG(argv[0]);
6846 len = NUM2LONG(argv[1]);
6847 val = argv[2];
6848 StringValue(val);
6849 if (argc == 3) {
6850 /* bytesplice(index, length, str) */
6851 vbeg = 0;
6852 vlen = RSTRING_LEN(val);
6853 }
6854 else {
6855 /* bytesplice(index, length, str, str_index, str_length) */
6856 vbeg = NUM2LONG(argv[3]);
6857 vlen = NUM2LONG(argv[4]);
6858 }
6859 }
6860 str_check_beg_len(str, &beg, &len);
6861 str_check_beg_len(val, &vbeg, &vlen);
6862 str_modify_keep_cr(str);
6863
6864 if (RB_UNLIKELY(ENCODING_GET_INLINED(str) != ENCODING_GET_INLINED(val))) {
6865 rb_enc_associate(str, rb_enc_check(str, val));
6866 }
6867
6868 rb_str_update_1(str, beg, len, val, vbeg, vlen);
6870 if (cr != ENC_CODERANGE_BROKEN)
6871 ENC_CODERANGE_SET(str, cr);
6872 return str;
6873}
6874
6875/*
6876 * call-seq:
6877 * reverse -> new_string
6878 *
6879 * Returns a new string with the characters from +self+ in reverse order.
6880 *
6881 * 'drawer'.reverse # => "reward"
6882 * 'reviled'.reverse # => "deliver"
6883 * 'stressed'.reverse # => "desserts"
6884 * 'semordnilaps'.reverse # => "spalindromes"
6885 *
6886 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
6887 */
6888
6889static VALUE
6890rb_str_reverse(VALUE str)
6891{
6892 rb_encoding *enc;
6893 VALUE rev;
6894 char *s, *e, *p;
6895 int cr;
6896
6897 if (RSTRING_LEN(str) <= 1) return str_duplicate(rb_cString, str);
6898 enc = STR_ENC_GET(str);
6899 rev = rb_str_new(0, RSTRING_LEN(str));
6900 s = RSTRING_PTR(str); e = RSTRING_END(str);
6901 p = RSTRING_END(rev);
6902 cr = ENC_CODERANGE(str);
6903
6904 if (RSTRING_LEN(str) > 1) {
6905 if (single_byte_optimizable(str)) {
6906 while (s < e) {
6907 *--p = *s++;
6908 }
6909 }
6910 else if (cr == ENC_CODERANGE_VALID) {
6911 while (s < e) {
6912 int clen = rb_enc_fast_mbclen(s, e, enc);
6913
6914 p -= clen;
6915 memcpy(p, s, clen);
6916 s += clen;
6917 }
6918 }
6919 else {
6920 cr = rb_enc_asciicompat(enc) ?
6922 while (s < e) {
6923 int clen = rb_enc_mbclen(s, e, enc);
6924
6925 if (clen > 1 || (*s & 0x80)) cr = ENC_CODERANGE_UNKNOWN;
6926 p -= clen;
6927 memcpy(p, s, clen);
6928 s += clen;
6929 }
6930 }
6931 }
6932 STR_SET_LEN(rev, RSTRING_LEN(str));
6933 str_enc_copy_direct(rev, str);
6934 ENC_CODERANGE_SET(rev, cr);
6935
6936 return rev;
6937}
6938
6939
6940/*
6941 * call-seq:
6942 * reverse! -> self
6943 *
6944 * Returns +self+ with its characters reversed:
6945 *
6946 * 'drawer'.reverse! # => "reward"
6947 * 'reviled'.reverse! # => "deliver"
6948 * 'stressed'.reverse! # => "desserts"
6949 * 'semordnilaps'.reverse! # => "spalindromes"
6950 *
6951 * Related: see {Modifying}[rdoc-ref:String@Modifying].
6952 */
6953
6954static VALUE
6955rb_str_reverse_bang(VALUE str)
6956{
6957 if (RSTRING_LEN(str) > 1) {
6958 if (single_byte_optimizable(str)) {
6959 char *s, *e, c;
6960
6961 str_modify_keep_cr(str);
6962 s = RSTRING_PTR(str);
6963 e = RSTRING_END(str) - 1;
6964 while (s < e) {
6965 c = *s;
6966 *s++ = *e;
6967 *e-- = c;
6968 }
6969 }
6970 else {
6971 str_shared_replace(str, rb_str_reverse(str));
6972 }
6973 }
6974 else {
6975 str_modify_keep_cr(str);
6976 }
6977 return str;
6978}
6979
6980
6981/*
6982 * call-seq:
6983 * include?(other_string) -> true or false
6984 *
6985 * Returns whether +self+ contains +other_string+:
6986 *
6987 * s = 'bar'
6988 * s.include?('ba') # => true
6989 * s.include?('ar') # => true
6990 * s.include?('bar') # => true
6991 * s.include?('a') # => true
6992 * s.include?('') # => true
6993 * s.include?('foo') # => false
6994 *
6995 * Related: see {Querying}[rdoc-ref:String@Querying].
6996 */
6997
6998VALUE
6999rb_str_include(VALUE str, VALUE arg)
7000{
7001 long i;
7002
7003 StringValue(arg);
7004 i = rb_str_index(str, arg, 0);
7005
7006 return RBOOL(i != -1);
7007}
7008
7009
7010/*
7011 * call-seq:
7012 * to_i(base = 10) -> integer
7013 *
7014 * Returns the result of interpreting leading characters in +self+
7015 * as an integer in the given +base+;
7016 * +base+ must be either +0+ or in range <tt>(2..36)</tt>:
7017 *
7018 * '123456'.to_i # => 123456
7019 * '123def'.to_i(16) # => 1195503
7020 *
7021 * With +base+ zero given, string +object+ may contain leading characters
7022 * to specify the actual base:
7023 *
7024 * '123def'.to_i(0) # => 123
7025 * '0123def'.to_i(0) # => 83
7026 * '0b123def'.to_i(0) # => 1
7027 * '0o123def'.to_i(0) # => 83
7028 * '0d123def'.to_i(0) # => 123
7029 * '0x123def'.to_i(0) # => 1195503
7030 *
7031 * Characters past a leading valid number (in the given +base+) are ignored:
7032 *
7033 * '12.345'.to_i # => 12
7034 * '12345'.to_i(2) # => 1
7035 *
7036 * Returns zero if there is no leading valid number:
7037 *
7038 * 'abcdef'.to_i # => 0
7039 * '2'.to_i(2) # => 0
7040 *
7041 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
7042 */
7043
7044static VALUE
7045rb_str_to_i(int argc, VALUE *argv, VALUE str)
7046{
7047 int base = 10;
7048
7049 if (rb_check_arity(argc, 0, 1) && (base = NUM2INT(argv[0])) < 0) {
7050 rb_raise(rb_eArgError, "invalid radix %d", base);
7051 }
7052 return rb_str_to_inum(str, base, FALSE);
7053}
7054
7055
7056/*
7057 * call-seq:
7058 * to_f -> float
7059 *
7060 * Returns the result of interpreting leading characters in +self+ as a Float:
7061 *
7062 * '3.14159'.to_f # => 3.14159
7063 * '1.234e-2'.to_f # => 0.01234
7064 *
7065 * Characters past a leading valid number are ignored:
7066 *
7067 * '3.14 (pi to two places)'.to_f # => 3.14
7068 *
7069 * Returns zero if there is no leading valid number:
7070 *
7071 * 'abcdef'.to_f # => 0.0
7072 *
7073 * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
7074 */
7075
7076static VALUE
7077rb_str_to_f(VALUE str)
7078{
7079 return DBL2NUM(rb_str_to_dbl(str, FALSE));
7080}
7081
7082
7083/*
7084 * call-seq:
7085 * to_s -> self or new_string
7086 *
7087 * Returns +self+ if +self+ is a +String+,
7088 * or +self+ converted to a +String+ if +self+ is a subclass of +String+.
7089 *
7090 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7091 */
7092
7093static VALUE
7094rb_str_to_s(VALUE str)
7095{
7096 if (rb_obj_class(str) != rb_cString) {
7097 return str_duplicate(rb_cString, str);
7098 }
7099 return str;
7100}
7101
7102#if 0
7103static void
7104str_cat_char(VALUE str, unsigned int c, rb_encoding *enc)
7105{
7106 char s[RUBY_MAX_CHAR_LEN];
7107 int n = rb_enc_codelen(c, enc);
7108
7109 rb_enc_mbcput(c, s, enc);
7110 rb_enc_str_buf_cat(str, s, n, enc);
7111}
7112#endif
7113
7114#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */
7115
7116int
7117rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p)
7118{
7119 char buf[CHAR_ESC_LEN + 1];
7120 int l;
7121
7122#if SIZEOF_INT > 4
7123 c &= 0xffffffff;
7124#endif
7125 if (unicode_p) {
7126 if (c < 0x7F && ISPRINT(c)) {
7127 snprintf(buf, CHAR_ESC_LEN, "%c", c);
7128 }
7129 else if (c < 0x10000) {
7130 snprintf(buf, CHAR_ESC_LEN, "\\u%04X", c);
7131 }
7132 else {
7133 snprintf(buf, CHAR_ESC_LEN, "\\u{%X}", c);
7134 }
7135 }
7136 else {
7137 if (c < 0x100) {
7138 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", c);
7139 }
7140 else {
7141 snprintf(buf, CHAR_ESC_LEN, "\\x{%X}", c);
7142 }
7143 }
7144 l = (int)strlen(buf); /* CHAR_ESC_LEN cannot exceed INT_MAX */
7145 rb_str_buf_cat(result, buf, l);
7146 return l;
7147}
7148
7149const char *
7150ruby_escaped_char(int c)
7151{
7152 switch (c) {
7153 case '\0': return "\\0";
7154 case '\n': return "\\n";
7155 case '\r': return "\\r";
7156 case '\t': return "\\t";
7157 case '\f': return "\\f";
7158 case '\013': return "\\v";
7159 case '\010': return "\\b";
7160 case '\007': return "\\a";
7161 case '\033': return "\\e";
7162 case '\x7f': return "\\c?";
7163 }
7164 return NULL;
7165}
7166
7167VALUE
7168rb_str_escape(VALUE str)
7169{
7170 int encidx = ENCODING_GET(str);
7171 rb_encoding *enc = rb_enc_from_index(encidx);
7172 const char *p = RSTRING_PTR(str);
7173 const char *pend = RSTRING_END(str);
7174 const char *prev = p;
7175 char buf[CHAR_ESC_LEN + 1];
7176 VALUE result = rb_str_buf_new(0);
7177 int unicode_p = rb_enc_unicode_p(enc);
7178 int asciicompat = rb_enc_asciicompat(enc);
7179
7180 while (p < pend) {
7181 unsigned int c;
7182 const char *cc;
7183 int n = rb_enc_precise_mbclen(p, pend, enc);
7184 if (!MBCLEN_CHARFOUND_P(n)) {
7185 if (p > prev) str_buf_cat(result, prev, p - prev);
7186 n = rb_enc_mbminlen(enc);
7187 if (pend < p + n)
7188 n = (int)(pend - p);
7189 while (n--) {
7190 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
7191 str_buf_cat(result, buf, strlen(buf));
7192 prev = ++p;
7193 }
7194 continue;
7195 }
7196 n = MBCLEN_CHARFOUND_LEN(n);
7197 c = rb_enc_mbc_to_codepoint(p, pend, enc);
7198 p += n;
7199 cc = ruby_escaped_char(c);
7200 if (cc) {
7201 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7202 str_buf_cat(result, cc, strlen(cc));
7203 prev = p;
7204 }
7205 else if (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c)) {
7206 }
7207 else {
7208 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7209 rb_str_buf_cat_escaped_char(result, c, unicode_p);
7210 prev = p;
7211 }
7212 }
7213 if (p > prev) str_buf_cat(result, prev, p - prev);
7214 ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
7215
7216 return result;
7217}
7218
7219/*
7220 * call-seq:
7221 * inspect -> string
7222 *
7223 * :include: doc/string/inspect.rdoc
7224 *
7225 */
7226
7227VALUE
7229{
7230 int encidx = ENCODING_GET(str);
7231 rb_encoding *enc = rb_enc_from_index(encidx);
7232 const char *p, *pend, *prev;
7233 char buf[CHAR_ESC_LEN + 1];
7234 VALUE result = rb_str_buf_new(0);
7235 rb_encoding *resenc = rb_default_internal_encoding();
7236 int unicode_p = rb_enc_unicode_p(enc);
7237 int asciicompat = rb_enc_asciicompat(enc);
7238
7239 if (resenc == NULL) resenc = rb_default_external_encoding();
7240 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
7241 rb_enc_associate(result, resenc);
7242 str_buf_cat2(result, "\"");
7243
7244 p = RSTRING_PTR(str); pend = RSTRING_END(str);
7245 prev = p;
7246 while (p < pend) {
7247 unsigned int c, cc;
7248 int n;
7249
7250 n = rb_enc_precise_mbclen(p, pend, enc);
7251 if (!MBCLEN_CHARFOUND_P(n)) {
7252 if (p > prev) str_buf_cat(result, prev, p - prev);
7253 n = rb_enc_mbminlen(enc);
7254 if (pend < p + n)
7255 n = (int)(pend - p);
7256 while (n--) {
7257 snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
7258 str_buf_cat(result, buf, strlen(buf));
7259 prev = ++p;
7260 }
7261 continue;
7262 }
7263 n = MBCLEN_CHARFOUND_LEN(n);
7264 c = rb_enc_mbc_to_codepoint(p, pend, enc);
7265 p += n;
7266 if ((asciicompat || unicode_p) &&
7267 (c == '"'|| c == '\\' ||
7268 (c == '#' &&
7269 p < pend &&
7270 MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
7271 (cc = rb_enc_codepoint(p,pend,enc),
7272 (cc == '$' || cc == '@' || cc == '{'))))) {
7273 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7274 str_buf_cat2(result, "\\");
7275 if (asciicompat || enc == resenc) {
7276 prev = p - n;
7277 continue;
7278 }
7279 }
7280 switch (c) {
7281 case '\n': cc = 'n'; break;
7282 case '\r': cc = 'r'; break;
7283 case '\t': cc = 't'; break;
7284 case '\f': cc = 'f'; break;
7285 case '\013': cc = 'v'; break;
7286 case '\010': cc = 'b'; break;
7287 case '\007': cc = 'a'; break;
7288 case 033: cc = 'e'; break;
7289 default: cc = 0; break;
7290 }
7291 if (cc) {
7292 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7293 buf[0] = '\\';
7294 buf[1] = (char)cc;
7295 str_buf_cat(result, buf, 2);
7296 prev = p;
7297 continue;
7298 }
7299 /* The special casing of 0x85 (NEXT_LINE) here is because
7300 * Oniguruma historically treats it as printable, but it
7301 * doesn't match the print POSIX bracket class or character
7302 * property in regexps.
7303 *
7304 * See Ruby Bug #16842 for details:
7305 * https://bugs.ruby-lang.org/issues/16842
7306 */
7307 if ((enc == resenc && rb_enc_isprint(c, enc) && c != 0x85) ||
7308 (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c))) {
7309 continue;
7310 }
7311 else {
7312 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
7313 rb_str_buf_cat_escaped_char(result, c, unicode_p);
7314 prev = p;
7315 continue;
7316 }
7317 }
7318 if (p > prev) str_buf_cat(result, prev, p - prev);
7319 str_buf_cat2(result, "\"");
7320
7321 return result;
7322}
7323
7324#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
7325
7326/*
7327 * call-seq:
7328 * dump -> new_string
7329 *
7330 * :include: doc/string/dump.rdoc
7331 *
7332 */
7333
7334VALUE
7336{
7337 int encidx = rb_enc_get_index(str);
7338 rb_encoding *enc = rb_enc_from_index(encidx);
7339 long len;
7340 const char *p, *pend;
7341 char *q, *qend;
7342 VALUE result;
7343 int u8 = (encidx == rb_utf8_encindex());
7344 static const char nonascii_suffix[] = ".dup.force_encoding(\"%s\")";
7345
7346 len = 2; /* "" */
7347 if (!rb_enc_asciicompat(enc)) {
7348 len += strlen(nonascii_suffix) - rb_strlen_lit("%s");
7349 len += strlen(enc->name);
7350 }
7351
7352 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
7353 while (p < pend) {
7354 int clen;
7355 unsigned char c = *p++;
7356
7357 switch (c) {
7358 case '"': case '\\':
7359 case '\n': case '\r':
7360 case '\t': case '\f':
7361 case '\013': case '\010': case '\007': case '\033':
7362 clen = 2;
7363 break;
7364
7365 case '#':
7366 clen = IS_EVSTR(p, pend) ? 2 : 1;
7367 break;
7368
7369 default:
7370 if (ISPRINT(c)) {
7371 clen = 1;
7372 }
7373 else {
7374 if (u8 && c > 0x7F) { /* \u notation */
7375 int n = rb_enc_precise_mbclen(p-1, pend, enc);
7376 if (MBCLEN_CHARFOUND_P(n)) {
7377 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
7378 if (cc <= 0xFFFF)
7379 clen = 6; /* \uXXXX */
7380 else if (cc <= 0xFFFFF)
7381 clen = 9; /* \u{XXXXX} */
7382 else
7383 clen = 10; /* \u{XXXXXX} */
7384 p += MBCLEN_CHARFOUND_LEN(n)-1;
7385 break;
7386 }
7387 }
7388 clen = 4; /* \xNN */
7389 }
7390 break;
7391 }
7392
7393 if (clen > LONG_MAX - len) {
7394 rb_raise(rb_eRuntimeError, "string size too big");
7395 }
7396 len += clen;
7397 }
7398
7399 result = rb_str_new(0, len);
7400 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
7401 q = RSTRING_PTR(result); qend = q + len + 1;
7402
7403 *q++ = '"';
7404 while (p < pend) {
7405 unsigned char c = *p++;
7406
7407 if (c == '"' || c == '\\') {
7408 *q++ = '\\';
7409 *q++ = c;
7410 }
7411 else if (c == '#') {
7412 if (IS_EVSTR(p, pend)) *q++ = '\\';
7413 *q++ = '#';
7414 }
7415 else if (c == '\n') {
7416 *q++ = '\\';
7417 *q++ = 'n';
7418 }
7419 else if (c == '\r') {
7420 *q++ = '\\';
7421 *q++ = 'r';
7422 }
7423 else if (c == '\t') {
7424 *q++ = '\\';
7425 *q++ = 't';
7426 }
7427 else if (c == '\f') {
7428 *q++ = '\\';
7429 *q++ = 'f';
7430 }
7431 else if (c == '\013') {
7432 *q++ = '\\';
7433 *q++ = 'v';
7434 }
7435 else if (c == '\010') {
7436 *q++ = '\\';
7437 *q++ = 'b';
7438 }
7439 else if (c == '\007') {
7440 *q++ = '\\';
7441 *q++ = 'a';
7442 }
7443 else if (c == '\033') {
7444 *q++ = '\\';
7445 *q++ = 'e';
7446 }
7447 else if (ISPRINT(c)) {
7448 *q++ = c;
7449 }
7450 else {
7451 *q++ = '\\';
7452 if (u8) {
7453 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
7454 if (MBCLEN_CHARFOUND_P(n)) {
7455 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
7456 p += n;
7457 if (cc <= 0xFFFF)
7458 snprintf(q, qend-q, "u%04X", cc); /* \uXXXX */
7459 else
7460 snprintf(q, qend-q, "u{%X}", cc); /* \u{XXXXX} or \u{XXXXXX} */
7461 q += strlen(q);
7462 continue;
7463 }
7464 }
7465 snprintf(q, qend-q, "x%02X", c);
7466 q += 3;
7467 }
7468 }
7469 *q++ = '"';
7470 *q = '\0';
7471 if (!rb_enc_asciicompat(enc)) {
7472 snprintf(q, qend-q, nonascii_suffix, enc->name);
7473 encidx = rb_ascii8bit_encindex();
7474 }
7475 /* result from dump is ASCII */
7476 rb_enc_associate_index(result, encidx);
7478 return result;
7479}
7480
7481static int
7482unescape_ascii(unsigned int c)
7483{
7484 switch (c) {
7485 case 'n':
7486 return '\n';
7487 case 'r':
7488 return '\r';
7489 case 't':
7490 return '\t';
7491 case 'f':
7492 return '\f';
7493 case 'v':
7494 return '\13';
7495 case 'b':
7496 return '\010';
7497 case 'a':
7498 return '\007';
7499 case 'e':
7500 return 033;
7501 }
7503}
7504
7505static void
7506undump_after_backslash(VALUE undumped, const char **ss, const char *s_end, rb_encoding **penc, bool *utf8, bool *binary)
7507{
7508 const char *s = *ss;
7509 unsigned int c;
7510 int codelen;
7511 size_t hexlen;
7512 unsigned char buf[6];
7513 static rb_encoding *enc_utf8 = NULL;
7514
7515 switch (*s) {
7516 case '\\':
7517 case '"':
7518 case '#':
7519 rb_str_cat(undumped, s, 1); /* cat itself */
7520 s++;
7521 break;
7522 case 'n':
7523 case 'r':
7524 case 't':
7525 case 'f':
7526 case 'v':
7527 case 'b':
7528 case 'a':
7529 case 'e':
7530 *buf = unescape_ascii(*s);
7531 rb_str_cat(undumped, (char *)buf, 1);
7532 s++;
7533 break;
7534 case 'u':
7535 if (*binary) {
7536 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
7537 }
7538 *utf8 = true;
7539 if (++s >= s_end) {
7540 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
7541 }
7542 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
7543 if (*penc != enc_utf8) {
7544 *penc = enc_utf8;
7545 rb_enc_associate(undumped, enc_utf8);
7546 }
7547 if (*s == '{') { /* handle \u{...} form */
7548 s++;
7549 for (;;) {
7550 if (s >= s_end) {
7551 rb_raise(rb_eRuntimeError, "unterminated Unicode escape");
7552 }
7553 if (*s == '}') {
7554 s++;
7555 break;
7556 }
7557 if (ISSPACE(*s)) {
7558 s++;
7559 continue;
7560 }
7561 c = scan_hex(s, s_end-s, &hexlen);
7562 if (hexlen == 0 || hexlen > 6) {
7563 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
7564 }
7565 if (c > 0x10ffff) {
7566 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint (too large)");
7567 }
7568 if (0xd800 <= c && c <= 0xdfff) {
7569 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
7570 }
7571 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
7572 rb_str_cat(undumped, (char *)buf, codelen);
7573 s += hexlen;
7574 }
7575 }
7576 else { /* handle \uXXXX form */
7577 c = scan_hex(s, 4, &hexlen);
7578 if (hexlen != 4) {
7579 rb_raise(rb_eRuntimeError, "invalid Unicode escape");
7580 }
7581 if (0xd800 <= c && c <= 0xdfff) {
7582 rb_raise(rb_eRuntimeError, "invalid Unicode codepoint");
7583 }
7584 codelen = rb_enc_mbcput(c, (char *)buf, *penc);
7585 rb_str_cat(undumped, (char *)buf, codelen);
7586 s += hexlen;
7587 }
7588 break;
7589 case 'x':
7590 if (++s >= s_end) {
7591 rb_raise(rb_eRuntimeError, "invalid hex escape");
7592 }
7593 *buf = scan_hex(s, 2, &hexlen);
7594 if (hexlen != 2) {
7595 rb_raise(rb_eRuntimeError, "invalid hex escape");
7596 }
7597 if (!ISASCII(*buf)) {
7598 if (*utf8) {
7599 rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
7600 }
7601 *binary = true;
7602 }
7603 rb_str_cat(undumped, (char *)buf, 1);
7604 s += hexlen;
7605 break;
7606 default:
7607 rb_str_cat(undumped, s-1, 2);
7608 s++;
7609 }
7610
7611 *ss = s;
7612}
7613
7614static VALUE rb_str_is_ascii_only_p(VALUE str);
7615
7616/*
7617 * call-seq:
7618 * undump -> new_string
7619 *
7620 * Inverse of String#dump; returns a copy of +self+ with changes of the kinds made by String#dump "undone."
7621 *
7622 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
7623 */
7624
7625static VALUE
7626str_undump(VALUE str)
7627{
7628 const char *s = RSTRING_PTR(str);
7629 const char *s_end = RSTRING_END(str);
7630 rb_encoding *enc = rb_enc_get(str);
7631 VALUE undumped = rb_enc_str_new(s, 0L, enc);
7632 bool utf8 = false;
7633 bool binary = false;
7634 int w;
7635
7637 if (rb_str_is_ascii_only_p(str) == Qfalse) {
7638 rb_raise(rb_eRuntimeError, "non-ASCII character detected");
7639 }
7640 if (!str_null_check(str, &w)) {
7641 rb_raise(rb_eRuntimeError, "string contains null byte");
7642 }
7643 if (RSTRING_LEN(str) < 2) goto invalid_format;
7644 if (*s != '"') goto invalid_format;
7645
7646 /* strip '"' at the start */
7647 s++;
7648
7649 for (;;) {
7650 if (s >= s_end) {
7651 rb_raise(rb_eRuntimeError, "unterminated dumped string");
7652 }
7653
7654 if (*s == '"') {
7655 /* epilogue */
7656 s++;
7657 if (s == s_end) {
7658 /* ascii compatible dumped string */
7659 break;
7660 }
7661 else {
7662 static const char force_encoding_suffix[] = ".force_encoding(\""; /* "\")" */
7663 static const char dup_suffix[] = ".dup";
7664 const char *encname;
7665 int encidx;
7666 ptrdiff_t size;
7667
7668 /* check separately for strings dumped by older versions */
7669 size = sizeof(dup_suffix) - 1;
7670 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
7671
7672 size = sizeof(force_encoding_suffix) - 1;
7673 if (s_end - s <= size) goto invalid_format;
7674 if (memcmp(s, force_encoding_suffix, size) != 0) goto invalid_format;
7675 s += size;
7676
7677 if (utf8) {
7678 rb_raise(rb_eRuntimeError, "dumped string contained Unicode escape but used force_encoding");
7679 }
7680
7681 encname = s;
7682 s = memchr(s, '"', s_end-s);
7683 size = s - encname;
7684 if (!s) goto invalid_format;
7685 if (s_end - s != 2) goto invalid_format;
7686 if (s[0] != '"' || s[1] != ')') goto invalid_format;
7687
7688 encidx = rb_enc_find_index2(encname, (long)size);
7689 if (encidx < 0) {
7690 rb_raise(rb_eRuntimeError, "dumped string has unknown encoding name");
7691 }
7692 rb_enc_associate_index(undumped, encidx);
7693 }
7694 break;
7695 }
7696
7697 if (*s == '\\') {
7698 s++;
7699 if (s >= s_end) {
7700 rb_raise(rb_eRuntimeError, "invalid escape");
7701 }
7702 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
7703 }
7704 else {
7705 rb_str_cat(undumped, s++, 1);
7706 }
7707 }
7708
7709 RB_GC_GUARD(str);
7710
7711 return undumped;
7712invalid_format:
7713 rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
7714}
7715
7716static void
7717rb_str_check_dummy_enc(rb_encoding *enc)
7718{
7719 if (rb_enc_dummy_p(enc)) {
7720 rb_raise(rb_eEncCompatError, "incompatible encoding with this operation: %s",
7721 rb_enc_name(enc));
7722 }
7723}
7724
7725static rb_encoding *
7726str_true_enc(VALUE str)
7727{
7728 rb_encoding *enc = STR_ENC_GET(str);
7729 rb_str_check_dummy_enc(enc);
7730 return enc;
7731}
7732
7733static OnigCaseFoldType
7734check_case_options(int argc, VALUE *argv, OnigCaseFoldType flags)
7735{
7736 if (argc==0)
7737 return flags;
7738 if (argc>2)
7739 rb_raise(rb_eArgError, "too many options");
7740 if (argv[0]==sym_turkic) {
7741 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
7742 if (argc==2) {
7743 if (argv[1]==sym_lithuanian)
7744 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
7745 else
7746 rb_raise(rb_eArgError, "invalid second option");
7747 }
7748 }
7749 else if (argv[0]==sym_lithuanian) {
7750 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
7751 if (argc==2) {
7752 if (argv[1]==sym_turkic)
7753 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
7754 else
7755 rb_raise(rb_eArgError, "invalid second option");
7756 }
7757 }
7758 else if (argc>1)
7759 rb_raise(rb_eArgError, "too many options");
7760 else if (argv[0]==sym_ascii)
7761 flags |= ONIGENC_CASE_ASCII_ONLY;
7762 else if (argv[0]==sym_fold) {
7763 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
7764 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
7765 else
7766 rb_raise(rb_eArgError, "option :fold only allowed for downcasing");
7767 }
7768 else
7769 rb_raise(rb_eArgError, "invalid option");
7770 return flags;
7771}
7772
7773static inline bool
7774case_option_single_p(OnigCaseFoldType flags, rb_encoding *enc, VALUE str)
7775{
7776 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() || rb_enc_mbmaxlen(enc) == 1))
7777 return true;
7778 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) && ENC_CODERANGE(str) == ENC_CODERANGE_7BIT;
7779}
7780
7781/* 16 should be long enough to absorb any kind of single character length increase */
7782#define CASE_MAPPING_ADDITIONAL_LENGTH 20
7783#ifndef CASEMAP_DEBUG
7784# define CASEMAP_DEBUG 0
7785#endif
7786
7787struct mapping_buffer;
7788typedef struct mapping_buffer {
7789 size_t capa;
7790 size_t used;
7791 struct mapping_buffer *next;
7792 OnigUChar space[FLEX_ARY_LEN];
7794
7795static void
7796mapping_buffer_free(void *p)
7797{
7798 mapping_buffer *previous_buffer;
7799 mapping_buffer *current_buffer = p;
7800 while (current_buffer) {
7801 previous_buffer = current_buffer;
7802 current_buffer = current_buffer->next;
7803 ruby_sized_xfree(previous_buffer, previous_buffer->capa);
7804 }
7805}
7806
7807static const rb_data_type_t mapping_buffer_type = {
7808 "mapping_buffer",
7809 {0, mapping_buffer_free,},
7810 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
7811};
7812
7813static VALUE
7814rb_str_casemap(VALUE source, OnigCaseFoldType *flags, rb_encoding *enc)
7815{
7816 VALUE target;
7817
7818 const OnigUChar *source_current, *source_end;
7819 int target_length = 0;
7820 VALUE buffer_anchor;
7821 mapping_buffer *current_buffer = 0;
7822 mapping_buffer **pre_buffer;
7823 size_t buffer_count = 0;
7824 int buffer_length_or_invalid;
7825
7826 if (RSTRING_LEN(source) == 0) return str_duplicate(rb_cString, source);
7827
7828 source_current = (OnigUChar*)RSTRING_PTR(source);
7829 source_end = (OnigUChar*)RSTRING_END(source);
7830
7831 buffer_anchor = TypedData_Wrap_Struct(0, &mapping_buffer_type, 0);
7832 pre_buffer = (mapping_buffer **)&DATA_PTR(buffer_anchor);
7833 while (source_current < source_end) {
7834 /* increase multiplier using buffer count to converge quickly */
7835 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
7836 if (CASEMAP_DEBUG) {
7837 fprintf(stderr, "Buffer allocation, capa is %"PRIuSIZE"\n", capa); /* for tuning */
7838 }
7839 current_buffer = xmalloc(offsetof(mapping_buffer, space) + capa);
7840 *pre_buffer = current_buffer;
7841 pre_buffer = &current_buffer->next;
7842 current_buffer->next = NULL;
7843 current_buffer->capa = capa;
7844 buffer_length_or_invalid = enc->case_map(flags,
7845 &source_current, source_end,
7846 current_buffer->space,
7847 current_buffer->space+current_buffer->capa,
7848 enc);
7849 if (buffer_length_or_invalid < 0) {
7850 current_buffer = DATA_PTR(buffer_anchor);
7851 DATA_PTR(buffer_anchor) = 0;
7852 mapping_buffer_free(current_buffer);
7853 rb_raise(rb_eArgError, "input string invalid");
7854 }
7855 target_length += current_buffer->used = buffer_length_or_invalid;
7856 }
7857 if (CASEMAP_DEBUG) {
7858 fprintf(stderr, "Buffer count is %"PRIuSIZE"\n", buffer_count); /* for tuning */
7859 }
7860
7861 if (buffer_count==1) {
7862 target = rb_str_new((const char*)current_buffer->space, target_length);
7863 }
7864 else {
7865 char *target_current;
7866
7867 target = rb_str_new(0, target_length);
7868 target_current = RSTRING_PTR(target);
7869 current_buffer = DATA_PTR(buffer_anchor);
7870 while (current_buffer) {
7871 memcpy(target_current, current_buffer->space, current_buffer->used);
7872 target_current += current_buffer->used;
7873 current_buffer = current_buffer->next;
7874 }
7875 }
7876 current_buffer = DATA_PTR(buffer_anchor);
7877 DATA_PTR(buffer_anchor) = 0;
7878 mapping_buffer_free(current_buffer);
7879
7880 RB_GC_GUARD(buffer_anchor);
7881
7882 /* TODO: check about string terminator character */
7883 str_enc_copy_direct(target, source);
7884 /*ENC_CODERANGE_SET(mapped, cr);*/
7885
7886 return target;
7887}
7888
7889static VALUE
7890rb_str_ascii_casemap(VALUE source, VALUE target, OnigCaseFoldType *flags, rb_encoding *enc)
7891{
7892 const OnigUChar *source_current, *source_end;
7893 OnigUChar *target_current, *target_end;
7894 long old_length = RSTRING_LEN(source);
7895 int length_or_invalid;
7896
7897 if (old_length == 0) return Qnil;
7898
7899 source_current = (OnigUChar*)RSTRING_PTR(source);
7900 source_end = (OnigUChar*)RSTRING_END(source);
7901 if (source == target) {
7902 target_current = (OnigUChar*)source_current;
7903 target_end = (OnigUChar*)source_end;
7904 }
7905 else {
7906 target_current = (OnigUChar*)RSTRING_PTR(target);
7907 target_end = (OnigUChar*)RSTRING_END(target);
7908 }
7909
7910 length_or_invalid = onigenc_ascii_only_case_map(flags,
7911 &source_current, source_end,
7912 target_current, target_end, enc);
7913 if (length_or_invalid < 0)
7914 rb_raise(rb_eArgError, "input string invalid");
7915 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
7916 fprintf(stderr, "problem with rb_str_ascii_casemap"
7917 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
7918 rb_raise(rb_eArgError, "internal problem with rb_str_ascii_casemap"
7919 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
7920 }
7921
7922 str_enc_copy(target, source);
7923
7924 return target;
7925}
7926
7927static bool
7928upcase_single(VALUE str)
7929{
7930 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
7931 bool modified = false;
7932
7933 while (s < send) {
7934 unsigned int c = *(unsigned char*)s;
7935
7936 if ('a' <= c && c <= 'z') {
7937 *s = 'A' + (c - 'a');
7938 modified = true;
7939 }
7940 s++;
7941 }
7942 return modified;
7943}
7944
7945/*
7946 * call-seq:
7947 * upcase!(mapping) -> self or nil
7948 *
7949 * Like String#upcase, except that:
7950 *
7951 * - Changes character casings in +self+ (not in a copy of +self+).
7952 * - Returns +self+ if any changes are made, +nil+ otherwise.
7953 *
7954 * Related: See {Modifying}[rdoc-ref:String@Modifying].
7955 */
7956
7957static VALUE
7958rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
7959{
7960 rb_encoding *enc;
7961 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
7962
7963 flags = check_case_options(argc, argv, flags);
7964 str_modify_keep_cr(str);
7965 enc = str_true_enc(str);
7966 if (case_option_single_p(flags, enc, str)) {
7967 if (upcase_single(str))
7968 flags |= ONIGENC_CASE_MODIFIED;
7969 }
7970 else if (flags&ONIGENC_CASE_ASCII_ONLY)
7971 rb_str_ascii_casemap(str, str, &flags, enc);
7972 else
7973 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
7974
7975 if (ONIGENC_CASE_MODIFIED&flags) return str;
7976 return Qnil;
7977}
7978
7979
7980/*
7981 * call-seq:
7982 * upcase(mapping = :ascii) -> new_string
7983 *
7984 * :include: doc/string/upcase.rdoc
7985 */
7986
7987static VALUE
7988rb_str_upcase(int argc, VALUE *argv, VALUE str)
7989{
7990 rb_encoding *enc;
7991 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
7992 VALUE ret;
7993
7994 flags = check_case_options(argc, argv, flags);
7995 enc = str_true_enc(str);
7996 if (case_option_single_p(flags, enc, str)) {
7997 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
7998 str_enc_copy_direct(ret, str);
7999 upcase_single(ret);
8000 }
8001 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8002 ret = rb_str_new(0, RSTRING_LEN(str));
8003 rb_str_ascii_casemap(str, ret, &flags, enc);
8004 }
8005 else {
8006 ret = rb_str_casemap(str, &flags, enc);
8007 }
8008
8009 return ret;
8010}
8011
8012static bool
8013downcase_single(VALUE str)
8014{
8015 char *s = RSTRING_PTR(str), *send = RSTRING_END(str);
8016 bool modified = false;
8017
8018 while (s < send) {
8019 unsigned int c = *(unsigned char*)s;
8020
8021 if ('A' <= c && c <= 'Z') {
8022 *s = 'a' + (c - 'A');
8023 modified = true;
8024 }
8025 s++;
8026 }
8027
8028 return modified;
8029}
8030
8031/*
8032 * call-seq:
8033 * downcase!(mapping) -> self or nil
8034 *
8035 * Like String#downcase, except that:
8036 *
8037 * - Changes character casings in +self+ (not in a copy of +self+).
8038 * - Returns +self+ if any changes are made, +nil+ otherwise.
8039 *
8040 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8041 */
8042
8043static VALUE
8044rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
8045{
8046 rb_encoding *enc;
8047 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8048
8049 flags = check_case_options(argc, argv, flags);
8050 str_modify_keep_cr(str);
8051 enc = str_true_enc(str);
8052 if (case_option_single_p(flags, enc, str)) {
8053 if (downcase_single(str))
8054 flags |= ONIGENC_CASE_MODIFIED;
8055 }
8056 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8057 rb_str_ascii_casemap(str, str, &flags, enc);
8058 else
8059 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8060
8061 if (ONIGENC_CASE_MODIFIED&flags) return str;
8062 return Qnil;
8063}
8064
8065
8066/*
8067 * call-seq:
8068 * downcase(mapping = :ascii) -> new_string
8069 *
8070 * :include: doc/string/downcase.rdoc
8071 *
8072 */
8073
8074static VALUE
8075rb_str_downcase(int argc, VALUE *argv, VALUE str)
8076{
8077 rb_encoding *enc;
8078 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8079 VALUE ret;
8080
8081 flags = check_case_options(argc, argv, flags);
8082 enc = str_true_enc(str);
8083 if (case_option_single_p(flags, enc, str)) {
8084 ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8085 str_enc_copy_direct(ret, str);
8086 downcase_single(ret);
8087 }
8088 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8089 ret = rb_str_new(0, RSTRING_LEN(str));
8090 rb_str_ascii_casemap(str, ret, &flags, enc);
8091 }
8092 else {
8093 ret = rb_str_casemap(str, &flags, enc);
8094 }
8095
8096 return ret;
8097}
8098
8099
8100/*
8101 * call-seq:
8102 * capitalize!(mapping = :ascii) -> self or nil
8103 *
8104 * Like String#capitalize, except that:
8105 *
8106 * - Changes character casings in +self+ (not in a copy of +self+).
8107 * - Returns +self+ if any changes are made, +nil+ otherwise.
8108 *
8109 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8110 */
8111
8112static VALUE
8113rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
8114{
8115 rb_encoding *enc;
8116 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
8117
8118 flags = check_case_options(argc, argv, flags);
8119 str_modify_keep_cr(str);
8120 enc = str_true_enc(str);
8121 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
8122 if (flags&ONIGENC_CASE_ASCII_ONLY)
8123 rb_str_ascii_casemap(str, str, &flags, enc);
8124 else
8125 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8126
8127 if (ONIGENC_CASE_MODIFIED&flags) return str;
8128 return Qnil;
8129}
8130
8131
8132/*
8133 * call-seq:
8134 * capitalize(mapping = :ascii) -> new_string
8135 *
8136 * :include: doc/string/capitalize.rdoc
8137 *
8138 */
8139
8140static VALUE
8141rb_str_capitalize(int argc, VALUE *argv, VALUE str)
8142{
8143 rb_encoding *enc;
8144 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
8145 VALUE ret;
8146
8147 flags = check_case_options(argc, argv, flags);
8148 enc = str_true_enc(str);
8149 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str;
8150 if (flags&ONIGENC_CASE_ASCII_ONLY) {
8151 ret = rb_str_new(0, RSTRING_LEN(str));
8152 rb_str_ascii_casemap(str, ret, &flags, enc);
8153 }
8154 else {
8155 ret = rb_str_casemap(str, &flags, enc);
8156 }
8157 return ret;
8158}
8159
8160
8161/*
8162 * call-seq:
8163 * swapcase!(mapping) -> self or nil
8164 *
8165 * Like String#swapcase, except that:
8166 *
8167 * - Changes are made to +self+, not to copy of +self+.
8168 * - Returns +self+ if any changes are made, +nil+ otherwise.
8169 *
8170 * Related: see {Modifying}[rdoc-ref:String@Modifying].
8171 */
8172
8173static VALUE
8174rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
8175{
8176 rb_encoding *enc;
8177 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
8178
8179 flags = check_case_options(argc, argv, flags);
8180 str_modify_keep_cr(str);
8181 enc = str_true_enc(str);
8182 if (flags&ONIGENC_CASE_ASCII_ONLY)
8183 rb_str_ascii_casemap(str, str, &flags, enc);
8184 else
8185 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8186
8187 if (ONIGENC_CASE_MODIFIED&flags) return str;
8188 return Qnil;
8189}
8190
8191
8192/*
8193 * call-seq:
8194 * swapcase(mapping = :ascii) -> new_string
8195 *
8196 * :include: doc/string/swapcase.rdoc
8197 *
8198 */
8199
8200static VALUE
8201rb_str_swapcase(int argc, VALUE *argv, VALUE str)
8202{
8203 rb_encoding *enc;
8204 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
8205 VALUE ret;
8206
8207 flags = check_case_options(argc, argv, flags);
8208 enc = str_true_enc(str);
8209 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str_duplicate(rb_cString, str);
8210 if (flags&ONIGENC_CASE_ASCII_ONLY) {
8211 ret = rb_str_new(0, RSTRING_LEN(str));
8212 rb_str_ascii_casemap(str, ret, &flags, enc);
8213 }
8214 else {
8215 ret = rb_str_casemap(str, &flags, enc);
8216 }
8217 return ret;
8218}
8219
8220typedef unsigned char *USTR;
8221
8222struct tr {
8223 int gen;
8224 unsigned int now, max;
8225 char *p, *pend;
8226};
8227
8228static unsigned int
8229trnext(struct tr *t, rb_encoding *enc)
8230{
8231 int n;
8232
8233 for (;;) {
8234 nextpart:
8235 if (!t->gen) {
8236 if (t->p == t->pend) return -1;
8237 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '\\' && t->p + n < t->pend) {
8238 t->p += n;
8239 }
8240 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
8241 t->p += n;
8242 if (rb_enc_ascget(t->p, t->pend, &n, enc) == '-' && t->p + n < t->pend) {
8243 t->p += n;
8244 if (t->p < t->pend) {
8245 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
8246 t->p += n;
8247 if (t->now > c) {
8248 if (t->now < 0x80 && c < 0x80) {
8249 rb_raise(rb_eArgError,
8250 "invalid range \"%c-%c\" in string transliteration",
8251 t->now, c);
8252 }
8253 else {
8254 rb_raise(rb_eArgError, "invalid range in string transliteration");
8255 }
8256 continue; /* not reached */
8257 }
8258 else if (t->now < c) {
8259 t->gen = 1;
8260 t->max = c;
8261 }
8262 }
8263 }
8264 return t->now;
8265 }
8266 else {
8267 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
8268 if (t->now == t->max) {
8269 t->gen = 0;
8270 goto nextpart;
8271 }
8272 }
8273 if (t->now < t->max) {
8274 return t->now;
8275 }
8276 else {
8277 t->gen = 0;
8278 return t->max;
8279 }
8280 }
8281 }
8282}
8283
8284static VALUE rb_str_delete_bang(int,VALUE*,VALUE);
8285
8286static VALUE
8287tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
8288{
8289 const unsigned int errc = -1;
8290 unsigned int trans[256];
8291 rb_encoding *enc, *e1, *e2;
8292 struct tr trsrc, trrepl;
8293 int cflag = 0;
8294 unsigned int c, c0, last = 0;
8295 int modify = 0, i, l;
8296 unsigned char *s, *send;
8297 VALUE hash = 0;
8298 int singlebyte = single_byte_optimizable(str);
8299 int termlen;
8300 int cr;
8301
8302#define CHECK_IF_ASCII(c) \
8303 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
8304 (cr = ENC_CODERANGE_VALID) : 0)
8305
8306 StringValue(src);
8307 StringValue(repl);
8308 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
8309 if (RSTRING_LEN(repl) == 0) {
8310 return rb_str_delete_bang(1, &src, str);
8311 }
8312
8313 cr = ENC_CODERANGE(str);
8314 e1 = rb_enc_check(str, src);
8315 e2 = rb_enc_check(str, repl);
8316 if (e1 == e2) {
8317 enc = e1;
8318 }
8319 else {
8320 enc = rb_enc_check(src, repl);
8321 }
8322 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
8323 if (RSTRING_LEN(src) > 1 &&
8324 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) == '^' &&
8325 trsrc.p + l < trsrc.pend) {
8326 cflag = 1;
8327 trsrc.p += l;
8328 }
8329 trrepl.p = RSTRING_PTR(repl);
8330 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
8331 trsrc.gen = trrepl.gen = 0;
8332 trsrc.now = trrepl.now = 0;
8333 trsrc.max = trrepl.max = 0;
8334
8335 if (cflag) {
8336 for (i=0; i<256; i++) {
8337 trans[i] = 1;
8338 }
8339 while ((c = trnext(&trsrc, enc)) != errc) {
8340 if (c < 256) {
8341 trans[c] = errc;
8342 }
8343 else {
8344 if (!hash) hash = rb_hash_new();
8345 rb_hash_aset(hash, UINT2NUM(c), Qtrue);
8346 }
8347 }
8348 while ((c = trnext(&trrepl, enc)) != errc)
8349 /* retrieve last replacer */;
8350 last = trrepl.now;
8351 for (i=0; i<256; i++) {
8352 if (trans[i] != errc) {
8353 trans[i] = last;
8354 }
8355 }
8356 }
8357 else {
8358 unsigned int r;
8359
8360 for (i=0; i<256; i++) {
8361 trans[i] = errc;
8362 }
8363 while ((c = trnext(&trsrc, enc)) != errc) {
8364 r = trnext(&trrepl, enc);
8365 if (r == errc) r = trrepl.now;
8366 if (c < 256) {
8367 trans[c] = r;
8368 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
8369 }
8370 else {
8371 if (!hash) hash = rb_hash_new();
8372 rb_hash_aset(hash, UINT2NUM(c), UINT2NUM(r));
8373 }
8374 }
8375 }
8376
8377 if (cr == ENC_CODERANGE_VALID && rb_enc_asciicompat(e1))
8378 cr = ENC_CODERANGE_7BIT;
8379 str_modify_keep_cr(str);
8380 s = (unsigned char *)RSTRING_PTR(str); send = (unsigned char *)RSTRING_END(str);
8381 termlen = rb_enc_mbminlen(enc);
8382 if (sflag) {
8383 int clen, tlen;
8384 long offset, max = RSTRING_LEN(str);
8385 unsigned int save = -1;
8386 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
8387
8388 while (s < send) {
8389 int may_modify = 0;
8390
8391 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
8392 if (!MBCLEN_CHARFOUND_P(r)) {
8393 xfree(buf);
8394 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
8395 }
8396 clen = MBCLEN_CHARFOUND_LEN(r);
8397 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
8398
8399 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
8400
8401 s += clen;
8402 if (c < 256) {
8403 c = trans[c];
8404 }
8405 else if (hash) {
8406 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
8407 if (NIL_P(tmp)) {
8408 if (cflag) c = last;
8409 else c = errc;
8410 }
8411 else if (cflag) c = errc;
8412 else c = NUM2INT(tmp);
8413 }
8414 else {
8415 c = errc;
8416 }
8417 if (c != (unsigned int)-1) {
8418 if (save == c) {
8419 CHECK_IF_ASCII(c);
8420 continue;
8421 }
8422 save = c;
8423 tlen = rb_enc_codelen(c, enc);
8424 modify = 1;
8425 }
8426 else {
8427 save = -1;
8428 c = c0;
8429 if (enc != e1) may_modify = 1;
8430 }
8431 if ((offset = t - buf) + tlen > max) {
8432 size_t MAYBE_UNUSED(old) = max + termlen;
8433 max = offset + tlen + (send - s);
8434 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
8435 t = buf + offset;
8436 }
8437 rb_enc_mbcput(c, t, enc);
8438 if (may_modify && memcmp(s, t, tlen) != 0) {
8439 modify = 1;
8440 }
8441 CHECK_IF_ASCII(c);
8442 t += tlen;
8443 }
8444 if (!STR_EMBED_P(str)) {
8445 ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
8446 }
8447 TERM_FILL((char *)t, termlen);
8448 RSTRING(str)->as.heap.ptr = (char *)buf;
8449 STR_SET_LEN(str, t - buf);
8450 STR_SET_NOEMBED(str);
8451 RSTRING(str)->as.heap.aux.capa = max;
8452 }
8453 else if (rb_enc_mbmaxlen(enc) == 1 || (singlebyte && !hash)) {
8454 while (s < send) {
8455 c = (unsigned char)*s;
8456 if (trans[c] != errc) {
8457 if (!cflag) {
8458 c = trans[c];
8459 *s = c;
8460 modify = 1;
8461 }
8462 else {
8463 *s = last;
8464 modify = 1;
8465 }
8466 }
8467 CHECK_IF_ASCII(c);
8468 s++;
8469 }
8470 }
8471 else {
8472 int clen, tlen;
8473 long offset, max = (long)((send - s) * 1.2);
8474 unsigned char *buf = ALLOC_N(unsigned char, max + termlen), *t = buf;
8475
8476 while (s < send) {
8477 int may_modify = 0;
8478
8479 int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
8480 if (!MBCLEN_CHARFOUND_P(r)) {
8481 xfree(buf);
8482 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
8483 }
8484 clen = MBCLEN_CHARFOUND_LEN(r);
8485 c0 = c = rb_enc_mbc_to_codepoint((char *)s, (char *)send, e1);
8486
8487 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
8488
8489 if (c < 256) {
8490 c = trans[c];
8491 }
8492 else if (hash) {
8493 VALUE tmp = rb_hash_lookup(hash, UINT2NUM(c));
8494 if (NIL_P(tmp)) {
8495 if (cflag) c = last;
8496 else c = errc;
8497 }
8498 else if (cflag) c = errc;
8499 else c = NUM2INT(tmp);
8500 }
8501 else {
8502 c = cflag ? last : errc;
8503 }
8504 if (c != errc) {
8505 tlen = rb_enc_codelen(c, enc);
8506 modify = 1;
8507 }
8508 else {
8509 c = c0;
8510 if (enc != e1) may_modify = 1;
8511 }
8512 if ((offset = t - buf) + tlen > max) {
8513 size_t MAYBE_UNUSED(old) = max + termlen;
8514 max = offset + tlen + (long)((send - s) * 1.2);
8515 SIZED_REALLOC_N(buf, unsigned char, max + termlen, old);
8516 t = buf + offset;
8517 }
8518 if (s != t) {
8519 rb_enc_mbcput(c, t, enc);
8520 if (may_modify && memcmp(s, t, tlen) != 0) {
8521 modify = 1;
8522 }
8523 }
8524 CHECK_IF_ASCII(c);
8525 s += clen;
8526 t += tlen;
8527 }
8528 if (!STR_EMBED_P(str)) {
8529 ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
8530 }
8531 TERM_FILL((char *)t, termlen);
8532 RSTRING(str)->as.heap.ptr = (char *)buf;
8533 STR_SET_LEN(str, t - buf);
8534 STR_SET_NOEMBED(str);
8535 RSTRING(str)->as.heap.aux.capa = max;
8536 }
8537
8538 if (modify) {
8539 if (cr != ENC_CODERANGE_BROKEN)
8540 ENC_CODERANGE_SET(str, cr);
8541 rb_enc_associate(str, enc);
8542 return str;
8543 }
8544 return Qnil;
8545}
8546
8547
8548/*
8549 * call-seq:
8550 * tr!(selector, replacements) -> self or nil
8551 *
8552 * Like String#tr, except:
8553 *
8554 * - Performs substitutions in +self+ (not in a copy of +self+).
8555 * - Returns +self+ if any modifications were made, +nil+ otherwise.
8556 *
8557 * Related: {Modifying}[rdoc-ref:String@Modifying].
8558 */
8559
8560static VALUE
8561rb_str_tr_bang(VALUE str, VALUE src, VALUE repl)
8562{
8563 return tr_trans(str, src, repl, 0);
8564}
8565
8566
8567/*
8568 * call-seq:
8569 * tr(selector, replacements) -> new_string
8570 *
8571 * Returns a copy of +self+ with each character specified by string +selector+
8572 * translated to the corresponding character in string +replacements+.
8573 * The correspondence is _positional_:
8574 *
8575 * - Each occurrence of the first character specified by +selector+
8576 * is translated to the first character in +replacements+.
8577 * - Each occurrence of the second character specified by +selector+
8578 * is translated to the second character in +replacements+.
8579 * - And so on.
8580 *
8581 * Example:
8582 *
8583 * 'hello'.tr('el', 'ip') #=> "hippo"
8584 *
8585 * If +replacements+ is shorter than +selector+,
8586 * it is implicitly padded with its own last character:
8587 *
8588 * 'hello'.tr('aeiou', '-') # => "h-ll-"
8589 * 'hello'.tr('aeiou', 'AA-') # => "hAll-"
8590 *
8591 * Arguments +selector+ and +replacements+ must be valid character selectors
8592 * (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
8593 * and may use any of its valid forms, including negation, ranges, and escapes:
8594 *
8595 * 'hello'.tr('^aeiou', '-') # => "-e--o" # Negation.
8596 * 'ibm'.tr('b-z', 'a-z') # => "hal" # Range.
8597 * 'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret.
8598 * 'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen.
8599 * 'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash.
8600 *
8601 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8602 */
8603
8604static VALUE
8605rb_str_tr(VALUE str, VALUE src, VALUE repl)
8606{
8607 str = str_duplicate(rb_cString, str);
8608 tr_trans(str, src, repl, 0);
8609 return str;
8610}
8611
8612#define TR_TABLE_MAX (UCHAR_MAX+1)
8613#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
8614static void
8615tr_setup_table(VALUE str, char stable[TR_TABLE_SIZE], int first,
8616 VALUE *tablep, VALUE *ctablep, rb_encoding *enc)
8617{
8618 const unsigned int errc = -1;
8619 char buf[TR_TABLE_MAX];
8620 struct tr tr;
8621 unsigned int c;
8622 VALUE table = 0, ptable = 0;
8623 int i, l, cflag = 0;
8624
8625 tr.p = RSTRING_PTR(str); tr.pend = tr.p + RSTRING_LEN(str);
8626 tr.gen = tr.now = tr.max = 0;
8627
8628 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(tr.p, tr.pend, &l, enc) == '^') {
8629 cflag = 1;
8630 tr.p += l;
8631 }
8632 if (first) {
8633 for (i=0; i<TR_TABLE_MAX; i++) {
8634 stable[i] = 1;
8635 }
8636 stable[TR_TABLE_MAX] = cflag;
8637 }
8638 else if (stable[TR_TABLE_MAX] && !cflag) {
8639 stable[TR_TABLE_MAX] = 0;
8640 }
8641 for (i=0; i<TR_TABLE_MAX; i++) {
8642 buf[i] = cflag;
8643 }
8644
8645 while ((c = trnext(&tr, enc)) != errc) {
8646 if (c < TR_TABLE_MAX) {
8647 buf[(unsigned char)c] = !cflag;
8648 }
8649 else {
8650 VALUE key = UINT2NUM(c);
8651
8652 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
8653 if (cflag) {
8654 ptable = *ctablep;
8655 table = ptable ? ptable : rb_hash_new();
8656 *ctablep = table;
8657 }
8658 else {
8659 table = rb_hash_new();
8660 ptable = *tablep;
8661 *tablep = table;
8662 }
8663 }
8664 if (table && (!ptable || (cflag ^ !NIL_P(rb_hash_aref(ptable, key))))) {
8665 rb_hash_aset(table, key, Qtrue);
8666 }
8667 }
8668 }
8669 for (i=0; i<TR_TABLE_MAX; i++) {
8670 stable[i] = stable[i] && buf[i];
8671 }
8672 if (!table && !cflag) {
8673 *tablep = 0;
8674 }
8675}
8676
8677
8678static int
8679tr_find(unsigned int c, const char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
8680{
8681 if (c < TR_TABLE_MAX) {
8682 return table[c] != 0;
8683 }
8684 else {
8685 VALUE v = UINT2NUM(c);
8686
8687 if (del) {
8688 if (!NIL_P(rb_hash_lookup(del, v)) &&
8689 (!nodel || NIL_P(rb_hash_lookup(nodel, v)))) {
8690 return TRUE;
8691 }
8692 }
8693 else if (nodel && !NIL_P(rb_hash_lookup(nodel, v))) {
8694 return FALSE;
8695 }
8696 return table[TR_TABLE_MAX] ? TRUE : FALSE;
8697 }
8698}
8699
8700/*
8701 * call-seq:
8702 * delete!(*selectors) -> self or nil
8703 *
8704 * Like String#delete, but modifies +self+ in place;
8705 * returns +self+ if any characters were deleted, +nil+ otherwise.
8706 *
8707 * Related: see {Modifying}[rdoc-ref:String@Modifying].
8708 */
8709
8710static VALUE
8711rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
8712{
8713 char squeez[TR_TABLE_SIZE];
8714 rb_encoding *enc = 0;
8715 char *s, *send, *t;
8716 VALUE del = 0, nodel = 0;
8717 int modify = 0;
8718 int i, ascompat, cr;
8719
8720 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
8721 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
8722 for (i=0; i<argc; i++) {
8723 VALUE s = argv[i];
8724
8725 StringValue(s);
8726 enc = rb_enc_check(str, s);
8727 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
8728 }
8729
8730 str_modify_keep_cr(str);
8731 ascompat = rb_enc_asciicompat(enc);
8732 s = t = RSTRING_PTR(str);
8733 send = RSTRING_END(str);
8734 cr = ascompat ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
8735 while (s < send) {
8736 unsigned int c;
8737 int clen;
8738
8739 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
8740 if (squeez[c]) {
8741 modify = 1;
8742 }
8743 else {
8744 if (t != s) *t = c;
8745 t++;
8746 }
8747 s++;
8748 }
8749 else {
8750 c = rb_enc_codepoint_len(s, send, &clen, enc);
8751
8752 if (tr_find(c, squeez, del, nodel)) {
8753 modify = 1;
8754 }
8755 else {
8756 if (t != s) rb_enc_mbcput(c, t, enc);
8757 t += clen;
8759 }
8760 s += clen;
8761 }
8762 }
8763 TERM_FILL(t, TERM_LEN(str));
8764 STR_SET_LEN(str, t - RSTRING_PTR(str));
8765 ENC_CODERANGE_SET(str, cr);
8766
8767 if (modify) return str;
8768 return Qnil;
8769}
8770
8771
8772/*
8773 * call-seq:
8774 * delete(*selectors) -> new_string
8775 *
8776 * :include: doc/string/delete.rdoc
8777 *
8778 */
8779
8780static VALUE
8781rb_str_delete(int argc, VALUE *argv, VALUE str)
8782{
8783 str = str_duplicate(rb_cString, str);
8784 rb_str_delete_bang(argc, argv, str);
8785 return str;
8786}
8787
8788
8789/*
8790 * call-seq:
8791 * squeeze!(*selectors) -> self or nil
8792 *
8793 * Like String#squeeze, except that:
8794 *
8795 * - Characters are squeezed in +self+ (not in a copy of +self+).
8796 * - Returns +self+ if any changes are made, +nil+ otherwise.
8797 *
8798 * Related: See {Modifying}[rdoc-ref:String@Modifying].
8799 */
8800
8801static VALUE
8802rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
8803{
8804 char squeez[TR_TABLE_SIZE];
8805 rb_encoding *enc = 0;
8806 VALUE del = 0, nodel = 0;
8807 unsigned char *s, *send, *t;
8808 int i, modify = 0;
8809 int ascompat, singlebyte = single_byte_optimizable(str);
8810 unsigned int save;
8811
8812 if (argc == 0) {
8813 enc = STR_ENC_GET(str);
8814 }
8815 else {
8816 for (i=0; i<argc; i++) {
8817 VALUE s = argv[i];
8818
8819 StringValue(s);
8820 enc = rb_enc_check(str, s);
8821 if (singlebyte && !single_byte_optimizable(s))
8822 singlebyte = 0;
8823 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
8824 }
8825 }
8826
8827 str_modify_keep_cr(str);
8828 s = t = (unsigned char *)RSTRING_PTR(str);
8829 if (!s || RSTRING_LEN(str) == 0) return Qnil;
8830 send = (unsigned char *)RSTRING_END(str);
8831 save = -1;
8832 ascompat = rb_enc_asciicompat(enc);
8833
8834 if (singlebyte) {
8835 while (s < send) {
8836 unsigned int c = *s++;
8837 if (c != save || (argc > 0 && !squeez[c])) {
8838 *t++ = save = c;
8839 }
8840 }
8841 }
8842 else {
8843 while (s < send) {
8844 unsigned int c;
8845 int clen;
8846
8847 if (ascompat && (c = *s) < 0x80) {
8848 if (c != save || (argc > 0 && !squeez[c])) {
8849 *t++ = save = c;
8850 }
8851 s++;
8852 }
8853 else {
8854 c = rb_enc_codepoint_len((char *)s, (char *)send, &clen, enc);
8855
8856 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
8857 if (t != s) rb_enc_mbcput(c, t, enc);
8858 save = c;
8859 t += clen;
8860 }
8861 s += clen;
8862 }
8863 }
8864 }
8865
8866 TERM_FILL((char *)t, TERM_LEN(str));
8867 if ((char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
8868 STR_SET_LEN(str, (char *)t - RSTRING_PTR(str));
8869 modify = 1;
8870 }
8871
8872 if (modify) return str;
8873 return Qnil;
8874}
8875
8876
8877/*
8878 * call-seq:
8879 * squeeze(*selectors) -> new_string
8880 *
8881 * :include: doc/string/squeeze.rdoc
8882 *
8883 */
8884
8885static VALUE
8886rb_str_squeeze(int argc, VALUE *argv, VALUE str)
8887{
8888 str = str_duplicate(rb_cString, str);
8889 rb_str_squeeze_bang(argc, argv, str);
8890 return str;
8891}
8892
8893
8894/*
8895 * call-seq:
8896 * tr_s!(selector, replacements) -> self or nil
8897 *
8898 * Like String#tr_s, except:
8899 *
8900 * - Modifies +self+ in place (not a copy of +self+).
8901 * - Returns +self+ if any changes were made, +nil+ otherwise.
8902 *
8903 * Related: {Modifying}[rdoc-ref:String@Modifying].
8904 */
8905
8906static VALUE
8907rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
8908{
8909 return tr_trans(str, src, repl, 1);
8910}
8911
8912
8913/*
8914 * call-seq:
8915 * tr_s(selector, replacements) -> new_string
8916 *
8917 * Like String#tr, except:
8918 *
8919 * - Also squeezes the modified portions of the translated string;
8920 * see String#squeeze.
8921 * - Returns the translated and squeezed string.
8922 *
8923 * Examples:
8924 *
8925 * 'hello'.tr_s('l', 'r') #=> "hero"
8926 * 'hello'.tr_s('el', '-') #=> "h-o"
8927 * 'hello'.tr_s('el', 'hx') #=> "hhxo"
8928 *
8929 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
8930 *
8931 */
8932
8933static VALUE
8934rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
8935{
8936 str = str_duplicate(rb_cString, str);
8937 tr_trans(str, src, repl, 1);
8938 return str;
8939}
8940
8941
8942/*
8943 * call-seq:
8944 * count(*selectors) -> integer
8945 *
8946 * :include: doc/string/count.rdoc
8947 */
8948
8949static VALUE
8950rb_str_count(int argc, VALUE *argv, VALUE str)
8951{
8952 char table[TR_TABLE_SIZE];
8953 rb_encoding *enc = 0;
8954 VALUE del = 0, nodel = 0, tstr;
8955 char *s, *send;
8956 int i;
8957 int ascompat;
8958 size_t n = 0;
8959
8960 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
8961
8962 tstr = argv[0];
8963 StringValue(tstr);
8964 enc = rb_enc_check(str, tstr);
8965 if (argc == 1) {
8966 const char *ptstr;
8967 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
8968 (ptstr = RSTRING_PTR(tstr),
8969 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
8970 !is_broken_string(str)) {
8971 int clen;
8972 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
8973
8974 s = RSTRING_PTR(str);
8975 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
8976 send = RSTRING_END(str);
8977 while (s < send) {
8978 if (*(unsigned char*)s++ == c) n++;
8979 }
8980 return SIZET2NUM(n);
8981 }
8982 }
8983
8984 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
8985 for (i=1; i<argc; i++) {
8986 tstr = argv[i];
8987 StringValue(tstr);
8988 enc = rb_enc_check(str, tstr);
8989 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
8990 }
8991
8992 s = RSTRING_PTR(str);
8993 if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
8994 send = RSTRING_END(str);
8995 ascompat = rb_enc_asciicompat(enc);
8996 while (s < send) {
8997 unsigned int c;
8998
8999 if (ascompat && (c = *(unsigned char*)s) < 0x80) {
9000 if (table[c]) {
9001 n++;
9002 }
9003 s++;
9004 }
9005 else {
9006 int clen;
9007 c = rb_enc_codepoint_len(s, send, &clen, enc);
9008 if (tr_find(c, table, del, nodel)) {
9009 n++;
9010 }
9011 s += clen;
9012 }
9013 }
9014
9015 return SIZET2NUM(n);
9016}
9017
9018static VALUE
9019rb_fs_check(VALUE val)
9020{
9021 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING) && !RB_TYPE_P(val, T_REGEXP)) {
9022 val = rb_check_string_type(val);
9023 if (NIL_P(val)) return 0;
9024 }
9025 return val;
9026}
9027
9028static const char isspacetable[256] = {
9029 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9030 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9031 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9032 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9033 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9034 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9035 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9036 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9037 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9038 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9039 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9040 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9041 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9043 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9044 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
9045};
9046
9047#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
9048
9049static long
9050split_string(VALUE result, VALUE str, long beg, long len, long empty_count)
9051{
9052 if (empty_count >= 0 && len == 0) {
9053 return empty_count + 1;
9054 }
9055 if (empty_count > 0) {
9056 /* make different substrings */
9057 if (result) {
9058 do {
9059 rb_ary_push(result, str_new_empty_String(str));
9060 } while (--empty_count > 0);
9061 }
9062 else {
9063 do {
9064 rb_yield(str_new_empty_String(str));
9065 } while (--empty_count > 0);
9066 }
9067 }
9068 str = rb_str_subseq(str, beg, len);
9069 if (result) {
9070 rb_ary_push(result, str);
9071 }
9072 else {
9073 rb_yield(str);
9074 }
9075 return empty_count;
9076}
9077
9078typedef enum {
9079 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
9080} split_type_t;
9081
9082static split_type_t
9083literal_split_pattern(VALUE spat, split_type_t default_type)
9084{
9085 rb_encoding *enc = STR_ENC_GET(spat);
9086 const char *ptr;
9087 long len;
9088 RSTRING_GETMEM(spat, ptr, len);
9089 if (len == 0) {
9090 /* Special case - split into chars */
9091 return SPLIT_TYPE_CHARS;
9092 }
9093 else if (rb_enc_asciicompat(enc)) {
9094 if (len == 1 && ptr[0] == ' ') {
9095 return SPLIT_TYPE_AWK;
9096 }
9097 }
9098 else {
9099 int l;
9100 if (rb_enc_ascget(ptr, ptr + len, &l, enc) == ' ' && len == l) {
9101 return SPLIT_TYPE_AWK;
9102 }
9103 }
9104 return default_type;
9105}
9106
9107/*
9108 * call-seq:
9109 * split(field_sep = $;, limit = 0) -> array_of_substrings
9110 * split(field_sep = $;, limit = 0) {|substring| ... } -> self
9111 *
9112 * :include: doc/string/split.rdoc
9113 *
9114 */
9115
9116static VALUE
9117rb_str_split_m(int argc, VALUE *argv, VALUE str)
9118{
9119 rb_encoding *enc;
9120 VALUE spat;
9121 VALUE limit;
9122 split_type_t split_type;
9123 long beg, end, i = 0, empty_count = -1;
9124 int lim = 0;
9125 VALUE result, tmp;
9126
9127 result = rb_block_given_p() ? Qfalse : Qnil;
9128 if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
9129 lim = NUM2INT(limit);
9130 if (lim <= 0) limit = Qnil;
9131 else if (lim == 1) {
9132 if (RSTRING_LEN(str) == 0)
9133 return result ? rb_ary_new2(0) : str;
9134 tmp = str_duplicate(rb_cString, str);
9135 if (!result) {
9136 rb_yield(tmp);
9137 return str;
9138 }
9139 return rb_ary_new3(1, tmp);
9140 }
9141 i = 1;
9142 }
9143 if (NIL_P(limit) && !lim) empty_count = 0;
9144
9145 enc = STR_ENC_GET(str);
9146 split_type = SPLIT_TYPE_REGEXP;
9147 if (!NIL_P(spat)) {
9148 spat = get_pat_quoted(spat, 0);
9149 }
9150 else if (NIL_P(spat = rb_fs)) {
9151 split_type = SPLIT_TYPE_AWK;
9152 }
9153 else if (!(spat = rb_fs_check(spat))) {
9154 rb_raise(rb_eTypeError, "value of $; must be String or Regexp");
9155 }
9156 else {
9157 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$; is set to non-nil value");
9158 }
9159 if (split_type != SPLIT_TYPE_AWK) {
9160 switch (BUILTIN_TYPE(spat)) {
9161 case T_REGEXP:
9162 rb_reg_options(spat); /* check if uninitialized */
9163 tmp = RREGEXP_SRC(spat);
9164 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
9165 if (split_type == SPLIT_TYPE_AWK) {
9166 spat = tmp;
9167 split_type = SPLIT_TYPE_STRING;
9168 }
9169 break;
9170
9171 case T_STRING:
9172 mustnot_broken(spat);
9173 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
9174 break;
9175
9176 default:
9178 }
9179 }
9180
9181#define SPLIT_STR(beg, len) ( \
9182 empty_count = split_string(result, str, beg, len, empty_count), \
9183 str_mod_check(str, str_start, str_len))
9184
9185 beg = 0;
9186 char *ptr = RSTRING_PTR(str);
9187 char *const str_start = ptr;
9188 const long str_len = RSTRING_LEN(str);
9189 char *const eptr = str_start + str_len;
9190 if (split_type == SPLIT_TYPE_AWK) {
9191 char *bptr = ptr;
9192 int skip = 1;
9193 unsigned int c;
9194
9195 if (result) result = rb_ary_new();
9196 end = beg;
9197 if (is_ascii_string(str)) {
9198 while (ptr < eptr) {
9199 c = (unsigned char)*ptr++;
9200 if (skip) {
9201 if (ascii_isspace(c)) {
9202 beg = ptr - bptr;
9203 }
9204 else {
9205 end = ptr - bptr;
9206 skip = 0;
9207 if (!NIL_P(limit) && lim <= i) break;
9208 }
9209 }
9210 else if (ascii_isspace(c)) {
9211 SPLIT_STR(beg, end-beg);
9212 skip = 1;
9213 beg = ptr - bptr;
9214 if (!NIL_P(limit)) ++i;
9215 }
9216 else {
9217 end = ptr - bptr;
9218 }
9219 }
9220 }
9221 else {
9222 while (ptr < eptr) {
9223 int n;
9224
9225 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
9226 ptr += n;
9227 if (skip) {
9228 if (rb_isspace(c)) {
9229 beg = ptr - bptr;
9230 }
9231 else {
9232 end = ptr - bptr;
9233 skip = 0;
9234 if (!NIL_P(limit) && lim <= i) break;
9235 }
9236 }
9237 else if (rb_isspace(c)) {
9238 SPLIT_STR(beg, end-beg);
9239 skip = 1;
9240 beg = ptr - bptr;
9241 if (!NIL_P(limit)) ++i;
9242 }
9243 else {
9244 end = ptr - bptr;
9245 }
9246 }
9247 }
9248 }
9249 else if (split_type == SPLIT_TYPE_STRING) {
9250 char *substr_start = ptr;
9251 char *sptr = RSTRING_PTR(spat);
9252 long slen = RSTRING_LEN(spat);
9253
9254 if (result) result = rb_ary_new();
9255 mustnot_broken(str);
9256 enc = rb_enc_check(str, spat);
9257 while (ptr < eptr &&
9258 (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
9259 /* Check we are at the start of a char */
9260 char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc);
9261 if (t != ptr + end) {
9262 ptr = t;
9263 continue;
9264 }
9265 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
9266 str_mod_check(spat, sptr, slen);
9267 ptr += end + slen;
9268 substr_start = ptr;
9269 if (!NIL_P(limit) && lim <= ++i) break;
9270 }
9271 beg = ptr - str_start;
9272 }
9273 else if (split_type == SPLIT_TYPE_CHARS) {
9274 int n;
9275
9276 if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
9277 mustnot_broken(str);
9278 enc = rb_enc_get(str);
9279 while (ptr < eptr &&
9280 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
9281 SPLIT_STR(ptr - str_start, n);
9282 ptr += n;
9283 if (!NIL_P(limit) && lim <= ++i) break;
9284 }
9285 beg = ptr - str_start;
9286 }
9287 else {
9288 if (result) result = rb_ary_new();
9289 long len = RSTRING_LEN(str);
9290 long start = beg;
9291 long idx;
9292 int last_null = 0;
9293 struct re_registers *regs;
9294 VALUE match = 0;
9295
9296 for (; rb_reg_search(spat, str, start, 0) >= 0;
9297 (match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
9298 match = rb_backref_get();
9299 if (!result) rb_match_busy(match);
9300 regs = RMATCH_REGS(match);
9301 end = BEG(0);
9302 if (start == end && BEG(0) == END(0)) {
9303 if (!ptr) {
9304 SPLIT_STR(0, 0);
9305 break;
9306 }
9307 else if (last_null == 1) {
9308 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
9309 beg = start;
9310 }
9311 else {
9312 if (start == len)
9313 start++;
9314 else
9315 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
9316 last_null = 1;
9317 continue;
9318 }
9319 }
9320 else {
9321 SPLIT_STR(beg, end-beg);
9322 beg = start = END(0);
9323 }
9324 last_null = 0;
9325
9326 for (idx=1; idx < regs->num_regs; idx++) {
9327 if (BEG(idx) == -1) continue;
9328 SPLIT_STR(BEG(idx), END(idx)-BEG(idx));
9329 }
9330 if (!NIL_P(limit) && lim <= ++i) break;
9331 }
9332 if (match) rb_match_unbusy(match);
9333 }
9334 if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
9335 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
9336 }
9337
9338 return result ? result : str;
9339}
9340
9341VALUE
9342rb_str_split(VALUE str, const char *sep0)
9343{
9344 VALUE sep;
9345
9346 StringValue(str);
9347 sep = rb_str_new_cstr(sep0);
9348 return rb_str_split_m(1, &sep, str);
9349}
9350
9351#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
9352
9353static inline int
9354enumerator_element(VALUE ary, VALUE e)
9355{
9356 if (ary) {
9357 rb_ary_push(ary, e);
9358 return 0;
9359 }
9360 else {
9361 rb_yield(e);
9362 return 1;
9363 }
9364}
9365
9366#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
9367
9368static const char *
9369chomp_newline(const char *p, const char *e, rb_encoding *enc)
9370{
9371 const char *prev = rb_enc_prev_char(p, e, e, enc);
9372 if (rb_enc_is_newline(prev, e, enc)) {
9373 e = prev;
9374 prev = rb_enc_prev_char(p, e, e, enc);
9375 if (prev && rb_enc_ascget(prev, e, NULL, enc) == '\r')
9376 e = prev;
9377 }
9378 return e;
9379}
9380
9381static VALUE
9382get_rs(void)
9383{
9384 VALUE rs = rb_rs;
9385 if (!NIL_P(rs) &&
9386 (!RB_TYPE_P(rs, T_STRING) ||
9387 RSTRING_LEN(rs) != 1 ||
9388 RSTRING_PTR(rs)[0] != '\n')) {
9389 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$/ is set to non-default value");
9390 }
9391 return rs;
9392}
9393
9394#define rb_rs get_rs()
9395
9396static VALUE
9397rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
9398{
9399 rb_encoding *enc;
9400 VALUE line, rs, orig = str, opts = Qnil, chomp = Qfalse;
9401 const char *ptr, *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
9402 long pos, len, rslen;
9403 int rsnewline = 0;
9404
9405 if (rb_scan_args(argc, argv, "01:", &rs, &opts) == 0)
9406 rs = rb_rs;
9407 if (!NIL_P(opts)) {
9408 static ID keywords[1];
9409 if (!keywords[0]) {
9410 keywords[0] = rb_intern_const("chomp");
9411 }
9412 rb_get_kwargs(opts, keywords, 0, 1, &chomp);
9413 chomp = (!UNDEF_P(chomp) && RTEST(chomp));
9414 }
9415
9416 if (NIL_P(rs)) {
9417 if (!ENUM_ELEM(ary, str)) {
9418 return ary;
9419 }
9420 else {
9421 return orig;
9422 }
9423 }
9424
9425 if (!RSTRING_LEN(str)) goto end;
9426 str = rb_str_new_frozen(str);
9427 ptr = subptr = RSTRING_PTR(str);
9428 pend = RSTRING_END(str);
9429 len = RSTRING_LEN(str);
9430 StringValue(rs);
9431 rslen = RSTRING_LEN(rs);
9432
9433 if (rs == rb_default_rs)
9434 enc = rb_enc_get(str);
9435 else
9436 enc = rb_enc_check(str, rs);
9437
9438 if (rslen == 0) {
9439 /* paragraph mode */
9440 int n;
9441 const char *eol = NULL;
9442 subend = subptr;
9443 while (subend < pend) {
9444 long chomp_rslen = 0;
9445 do {
9446 if (rb_enc_ascget(subend, pend, &n, enc) != '\r')
9447 n = 0;
9448 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
9449 if (rb_enc_is_newline(subend + n, pend, enc)) {
9450 if (eol == subend) break;
9451 subend += rslen;
9452 if (subptr) {
9453 eol = subend;
9454 chomp_rslen = -rslen;
9455 }
9456 }
9457 else {
9458 if (!subptr) subptr = subend;
9459 subend += rslen;
9460 }
9461 rslen = 0;
9462 } while (subend < pend);
9463 if (!subptr) break;
9464 if (rslen == 0) chomp_rslen = 0;
9465 line = rb_str_subseq(str, subptr - ptr,
9466 subend - subptr + (chomp ? chomp_rslen : rslen));
9467 if (ENUM_ELEM(ary, line)) {
9468 str_mod_check(str, ptr, len);
9469 }
9470 subptr = eol = NULL;
9471 }
9472 goto end;
9473 }
9474 else {
9475 rsptr = RSTRING_PTR(rs);
9476 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
9477 rb_enc_is_newline(rsptr, rsptr + RSTRING_LEN(rs), enc)) {
9478 rsnewline = 1;
9479 }
9480 }
9481
9482 if ((rs == rb_default_rs) && !rb_enc_asciicompat(enc)) {
9483 rs = rb_str_new(rsptr, rslen);
9484 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
9485 rsptr = RSTRING_PTR(rs);
9486 rslen = RSTRING_LEN(rs);
9487 }
9488
9489 while (subptr < pend) {
9490 pos = rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
9491 if (pos < 0) break;
9492 hit = subptr + pos;
9493 adjusted = rb_enc_right_char_head(subptr, hit, pend, enc);
9494 if (hit != adjusted) {
9495 subptr = adjusted;
9496 continue;
9497 }
9498 subend = hit += rslen;
9499 if (chomp) {
9500 if (rsnewline) {
9501 subend = chomp_newline(subptr, subend, enc);
9502 }
9503 else {
9504 subend -= rslen;
9505 }
9506 }
9507 line = rb_str_subseq(str, subptr - ptr, subend - subptr);
9508 if (ENUM_ELEM(ary, line)) {
9509 str_mod_check(str, ptr, len);
9510 }
9511 subptr = hit;
9512 }
9513
9514 if (subptr != pend) {
9515 if (chomp) {
9516 if (rsnewline) {
9517 pend = chomp_newline(subptr, pend, enc);
9518 }
9519 else if (pend - subptr >= rslen &&
9520 memcmp(pend - rslen, rsptr, rslen) == 0) {
9521 pend -= rslen;
9522 }
9523 }
9524 line = rb_str_subseq(str, subptr - ptr, pend - subptr);
9525 ENUM_ELEM(ary, line);
9526 RB_GC_GUARD(str);
9527 }
9528
9529 end:
9530 if (ary)
9531 return ary;
9532 else
9533 return orig;
9534}
9535
9536/*
9537 * call-seq:
9538 * each_line(record_separator = $/, chomp: false) {|substring| ... } -> self
9539 * each_line(record_separator = $/, chomp: false) -> enumerator
9540 *
9541 * :include: doc/string/each_line.rdoc
9542 *
9543 */
9544
9545static VALUE
9546rb_str_each_line(int argc, VALUE *argv, VALUE str)
9547{
9548 RETURN_SIZED_ENUMERATOR(str, argc, argv, 0);
9549 return rb_str_enumerate_lines(argc, argv, str, 0);
9550}
9551
9552/*
9553 * call-seq:
9554 * lines(record_separator = $/, chomp: false) -> array_of_strings
9555 *
9556 * Returns substrings ("lines") of +self+
9557 * according to the given arguments:
9558 *
9559 * s = <<~EOT
9560 * This is the first line.
9561 * This is line two.
9562 *
9563 * This is line four.
9564 * This is line five.
9565 * EOT
9566 *
9567 * With the default argument values:
9568 *
9569 * $/ # => "\n"
9570 * s.lines
9571 * # =>
9572 * ["This is the first line.\n",
9573 * "This is line two.\n",
9574 * "\n",
9575 * "This is line four.\n",
9576 * "This is line five.\n"]
9577 *
9578 * With a different +record_separator+:
9579 *
9580 * record_separator = ' is '
9581 * s.lines(record_separator)
9582 * # =>
9583 * ["This is ",
9584 * "the first line.\nThis is ",
9585 * "line two.\n\nThis is ",
9586 * "line four.\nThis is ",
9587 * "line five.\n"]
9588 *
9589 * With keyword argument +chomp+ as +true+,
9590 * removes the trailing newline from each line:
9591 *
9592 * s.lines(chomp: true)
9593 * # =>
9594 * ["This is the first line.",
9595 * "This is line two.",
9596 * "",
9597 * "This is line four.",
9598 * "This is line five."]
9599 *
9600 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
9601 */
9602
9603static VALUE
9604rb_str_lines(int argc, VALUE *argv, VALUE str)
9605{
9606 VALUE ary = WANTARRAY("lines", 0);
9607 return rb_str_enumerate_lines(argc, argv, str, ary);
9608}
9609
9610static VALUE
9611rb_str_each_byte_size(VALUE str, VALUE args, VALUE eobj)
9612{
9613 return LONG2FIX(RSTRING_LEN(str));
9614}
9615
9616static VALUE
9617rb_str_enumerate_bytes(VALUE str, VALUE ary)
9618{
9619 long i;
9620
9621 for (i=0; i<RSTRING_LEN(str); i++) {
9622 ENUM_ELEM(ary, INT2FIX((unsigned char)RSTRING_PTR(str)[i]));
9623 }
9624 if (ary)
9625 return ary;
9626 else
9627 return str;
9628}
9629
9630/*
9631 * call-seq:
9632 * each_byte {|byte| ... } -> self
9633 * each_byte -> enumerator
9634 *
9635 * :include: doc/string/each_byte.rdoc
9636 *
9637 */
9638
9639static VALUE
9640rb_str_each_byte(VALUE str)
9641{
9642 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_byte_size);
9643 return rb_str_enumerate_bytes(str, 0);
9644}
9645
9646/*
9647 * call-seq:
9648 * bytes -> array_of_bytes
9649 *
9650 * :include: doc/string/bytes.rdoc
9651 *
9652 */
9653
9654static VALUE
9655rb_str_bytes(VALUE str)
9656{
9657 VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
9658 return rb_str_enumerate_bytes(str, ary);
9659}
9660
9661static VALUE
9662rb_str_each_char_size(VALUE str, VALUE args, VALUE eobj)
9663{
9664 return rb_str_length(str);
9665}
9666
9667static VALUE
9668rb_str_enumerate_chars(VALUE str, VALUE ary)
9669{
9670 VALUE orig = str;
9671 long i, len, n;
9672 const char *ptr;
9673 rb_encoding *enc;
9674
9675 str = rb_str_new_frozen(str);
9676 ptr = RSTRING_PTR(str);
9677 len = RSTRING_LEN(str);
9678 enc = rb_enc_get(str);
9679
9681 for (i = 0; i < len; i += n) {
9682 n = rb_enc_fast_mbclen(ptr + i, ptr + len, enc);
9683 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
9684 }
9685 }
9686 else {
9687 for (i = 0; i < len; i += n) {
9688 n = rb_enc_mbclen(ptr + i, ptr + len, enc);
9689 ENUM_ELEM(ary, rb_str_subseq(str, i, n));
9690 }
9691 }
9692 RB_GC_GUARD(str);
9693 if (ary)
9694 return ary;
9695 else
9696 return orig;
9697}
9698
9699/*
9700 * call-seq:
9701 * each_char {|char| ... } -> self
9702 * each_char -> enumerator
9703 *
9704 * :include: doc/string/each_char.rdoc
9705 *
9706 */
9707
9708static VALUE
9709rb_str_each_char(VALUE str)
9710{
9711 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
9712 return rb_str_enumerate_chars(str, 0);
9713}
9714
9715/*
9716 * call-seq:
9717 * chars -> array_of_characters
9718 *
9719 * :include: doc/string/chars.rdoc
9720 *
9721 */
9722
9723static VALUE
9724rb_str_chars(VALUE str)
9725{
9726 VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
9727 return rb_str_enumerate_chars(str, ary);
9728}
9729
9730static VALUE
9731rb_str_enumerate_codepoints(VALUE str, VALUE ary)
9732{
9733 VALUE orig = str;
9734 int n;
9735 unsigned int c;
9736 const char *ptr, *end;
9737 rb_encoding *enc;
9738
9739 if (single_byte_optimizable(str))
9740 return rb_str_enumerate_bytes(str, ary);
9741
9742 str = rb_str_new_frozen(str);
9743 ptr = RSTRING_PTR(str);
9744 end = RSTRING_END(str);
9745 enc = STR_ENC_GET(str);
9746
9747 while (ptr < end) {
9748 c = rb_enc_codepoint_len(ptr, end, &n, enc);
9749 ENUM_ELEM(ary, UINT2NUM(c));
9750 ptr += n;
9751 }
9752 RB_GC_GUARD(str);
9753 if (ary)
9754 return ary;
9755 else
9756 return orig;
9757}
9758
9759/*
9760 * call-seq:
9761 * each_codepoint {|codepoint| ... } -> self
9762 * each_codepoint -> enumerator
9763 *
9764 * :include: doc/string/each_codepoint.rdoc
9765 *
9766 */
9767
9768static VALUE
9769rb_str_each_codepoint(VALUE str)
9770{
9771 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
9772 return rb_str_enumerate_codepoints(str, 0);
9773}
9774
9775/*
9776 * call-seq:
9777 * codepoints -> array_of_integers
9778 *
9779 * :include: doc/string/codepoints.rdoc
9780 *
9781 */
9782
9783static VALUE
9784rb_str_codepoints(VALUE str)
9785{
9786 VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
9787 return rb_str_enumerate_codepoints(str, ary);
9788}
9789
9790static regex_t *
9791get_reg_grapheme_cluster(rb_encoding *enc)
9792{
9793 int encidx = rb_enc_to_index(enc);
9794
9795 const OnigUChar source_ascii[] = "\\X";
9796 const OnigUChar *source = source_ascii;
9797 size_t source_len = sizeof(source_ascii) - 1;
9798
9799 switch (encidx) {
9800#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
9801#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
9802#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
9803#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
9804#define CASE_UTF(e) \
9805 case ENCINDEX_UTF_##e: { \
9806 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
9807 source = source_UTF_##e; \
9808 source_len = sizeof(source_UTF_##e); \
9809 break; \
9810 }
9811 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
9812#undef CASE_UTF
9813#undef CHARS_16BE
9814#undef CHARS_16LE
9815#undef CHARS_32BE
9816#undef CHARS_32LE
9817 }
9818
9819 regex_t *reg_grapheme_cluster;
9820 OnigErrorInfo einfo;
9821 int r = onig_new(&reg_grapheme_cluster, source, source + source_len,
9822 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
9823 if (r) {
9824 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
9825 onig_error_code_to_str(message, r, &einfo);
9826 rb_fatal("cannot compile grapheme cluster regexp: %s", (char *)message);
9827 }
9828
9829 return reg_grapheme_cluster;
9830}
9831
9832static regex_t *
9833get_cached_reg_grapheme_cluster(rb_encoding *enc)
9834{
9835 int encidx = rb_enc_to_index(enc);
9836 static regex_t *reg_grapheme_cluster_utf8 = NULL;
9837
9838 if (encidx == rb_utf8_encindex()) {
9839 if (!reg_grapheme_cluster_utf8) {
9840 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
9841 }
9842
9843 return reg_grapheme_cluster_utf8;
9844 }
9845
9846 return NULL;
9847}
9848
9849static VALUE
9850rb_str_each_grapheme_cluster_size(VALUE str, VALUE args, VALUE eobj)
9851{
9852 size_t grapheme_cluster_count = 0;
9853 rb_encoding *enc = get_encoding(str);
9854 const char *ptr, *end;
9855
9856 if (!rb_enc_unicode_p(enc)) {
9857 return rb_str_length(str);
9858 }
9859
9860 bool cached_reg_grapheme_cluster = true;
9861 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
9862 if (!reg_grapheme_cluster) {
9863 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
9864 cached_reg_grapheme_cluster = false;
9865 }
9866
9867 ptr = RSTRING_PTR(str);
9868 end = RSTRING_END(str);
9869
9870 while (ptr < end) {
9871 OnigPosition len = onig_match(reg_grapheme_cluster,
9872 (const OnigUChar *)ptr, (const OnigUChar *)end,
9873 (const OnigUChar *)ptr, NULL, 0);
9874 if (len <= 0) break;
9875 grapheme_cluster_count++;
9876 ptr += len;
9877 }
9878
9879 if (!cached_reg_grapheme_cluster) {
9880 onig_free(reg_grapheme_cluster);
9881 }
9882
9883 return SIZET2NUM(grapheme_cluster_count);
9884}
9885
9886static VALUE
9887rb_str_enumerate_grapheme_clusters(VALUE str, VALUE ary)
9888{
9889 VALUE orig = str;
9890 rb_encoding *enc = get_encoding(str);
9891 const char *ptr0, *ptr, *end;
9892
9893 if (!rb_enc_unicode_p(enc)) {
9894 return rb_str_enumerate_chars(str, ary);
9895 }
9896
9897 if (!ary) str = rb_str_new_frozen(str);
9898
9899 bool cached_reg_grapheme_cluster = true;
9900 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
9901 if (!reg_grapheme_cluster) {
9902 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
9903 cached_reg_grapheme_cluster = false;
9904 }
9905
9906 ptr0 = ptr = RSTRING_PTR(str);
9907 end = RSTRING_END(str);
9908
9909 while (ptr < end) {
9910 OnigPosition len = onig_match(reg_grapheme_cluster,
9911 (const OnigUChar *)ptr, (const OnigUChar *)end,
9912 (const OnigUChar *)ptr, NULL, 0);
9913 if (len <= 0) break;
9914 ENUM_ELEM(ary, rb_str_subseq(str, ptr-ptr0, len));
9915 ptr += len;
9916 }
9917
9918 if (!cached_reg_grapheme_cluster) {
9919 onig_free(reg_grapheme_cluster);
9920 }
9921
9922 RB_GC_GUARD(str);
9923 if (ary)
9924 return ary;
9925 else
9926 return orig;
9927}
9928
9929/*
9930 * call-seq:
9931 * each_grapheme_cluster {|grapheme_cluster| ... } -> self
9932 * each_grapheme_cluster -> enumerator
9933 *
9934 * :include: doc/string/each_grapheme_cluster.rdoc
9935 *
9936 */
9937
9938static VALUE
9939rb_str_each_grapheme_cluster(VALUE str)
9940{
9941 RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_grapheme_cluster_size);
9942 return rb_str_enumerate_grapheme_clusters(str, 0);
9943}
9944
9945/*
9946 * call-seq:
9947 * grapheme_clusters -> array_of_grapheme_clusters
9948 *
9949 * :include: doc/string/grapheme_clusters.rdoc
9950 *
9951 */
9952
9953static VALUE
9954rb_str_grapheme_clusters(VALUE str)
9955{
9956 VALUE ary = WANTARRAY("grapheme_clusters", rb_str_strlen(str));
9957 return rb_str_enumerate_grapheme_clusters(str, ary);
9958}
9959
9960static long
9961chopped_length(VALUE str)
9962{
9963 rb_encoding *enc = STR_ENC_GET(str);
9964 const char *p, *p2, *beg, *end;
9965
9966 beg = RSTRING_PTR(str);
9967 end = beg + RSTRING_LEN(str);
9968 if (beg >= end) return 0;
9969 p = rb_enc_prev_char(beg, end, end, enc);
9970 if (!p) return 0;
9971 if (p > beg && rb_enc_ascget(p, end, 0, enc) == '\n') {
9972 p2 = rb_enc_prev_char(beg, p, end, enc);
9973 if (p2 && rb_enc_ascget(p2, end, 0, enc) == '\r') p = p2;
9974 }
9975 return p - beg;
9976}
9977
9978/*
9979 * call-seq:
9980 * chop! -> self or nil
9981 *
9982 * Like String#chop, except that:
9983 *
9984 * - Removes trailing characters from +self+ (not from a copy of +self+).
9985 * - Returns +self+ if any characters are removed, +nil+ otherwise.
9986 *
9987 * Related: see {Modifying}[rdoc-ref:String@Modifying].
9988 */
9989
9990static VALUE
9991rb_str_chop_bang(VALUE str)
9992{
9993 str_modify_keep_cr(str);
9994 if (RSTRING_LEN(str) > 0) {
9995 long len;
9996 len = chopped_length(str);
9997 STR_SET_LEN(str, len);
9998 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
9999 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
10001 }
10002 return str;
10003 }
10004 return Qnil;
10005}
10006
10007
10008/*
10009 * call-seq:
10010 * chop -> new_string
10011 *
10012 * :include: doc/string/chop.rdoc
10013 *
10014 */
10015
10016static VALUE
10017rb_str_chop(VALUE str)
10018{
10019 return rb_str_subseq(str, 0, chopped_length(str));
10020}
10021
10022static long
10023smart_chomp(VALUE str, const char *e, const char *p)
10024{
10025 rb_encoding *enc = rb_enc_get(str);
10026 if (rb_enc_mbminlen(enc) > 1) {
10027 const char *pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
10028 if (rb_enc_is_newline(pp, e, enc)) {
10029 e = pp;
10030 }
10031 pp = e - rb_enc_mbminlen(enc);
10032 if (pp >= p) {
10033 pp = rb_enc_left_char_head(p, pp, e, enc);
10034 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
10035 e = pp;
10036 }
10037 }
10038 }
10039 else {
10040 switch (*(e-1)) { /* not e[-1] to get rid of VC bug */
10041 case '\n':
10042 if (--e > p && *(e-1) == '\r') {
10043 --e;
10044 }
10045 break;
10046 case '\r':
10047 --e;
10048 break;
10049 }
10050 }
10051 return e - p;
10052}
10053
10054static long
10055chompped_length(VALUE str, VALUE rs)
10056{
10057 rb_encoding *enc;
10058 int newline;
10059 char *pp, *e, *rsptr;
10060 long rslen;
10061 char *const p = RSTRING_PTR(str);
10062 long len = RSTRING_LEN(str);
10063
10064 if (len == 0) return 0;
10065 e = p + len;
10066 if (rs == rb_default_rs) {
10067 return smart_chomp(str, e, p);
10068 }
10069
10070 enc = rb_enc_get(str);
10071 RSTRING_GETMEM(rs, rsptr, rslen);
10072 if (rslen == 0) {
10073 if (rb_enc_mbminlen(enc) > 1) {
10074 while (e > p) {
10075 pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc);
10076 if (!rb_enc_is_newline(pp, e, enc)) break;
10077 e = pp;
10078 pp -= rb_enc_mbminlen(enc);
10079 if (pp >= p) {
10080 pp = rb_enc_left_char_head(p, pp, e, enc);
10081 if (rb_enc_ascget(pp, e, 0, enc) == '\r') {
10082 e = pp;
10083 }
10084 }
10085 }
10086 }
10087 else {
10088 while (e > p && *(e-1) == '\n') {
10089 --e;
10090 if (e > p && *(e-1) == '\r')
10091 --e;
10092 }
10093 }
10094 return e - p;
10095 }
10096 if (rslen > len) return len;
10097
10098 enc = rb_enc_get(rs);
10099 newline = rsptr[rslen-1];
10100 if (rslen == rb_enc_mbminlen(enc)) {
10101 if (rslen == 1) {
10102 if (newline == '\n')
10103 return smart_chomp(str, e, p);
10104 }
10105 else {
10106 if (rb_enc_is_newline(rsptr, rsptr+rslen, enc))
10107 return smart_chomp(str, e, p);
10108 }
10109 }
10110
10111 enc = rb_enc_check(str, rs);
10112 if (is_broken_string(rs)) {
10113 return len;
10114 }
10115 pp = e - rslen;
10116 if (p[len-1] == newline &&
10117 (rslen <= 1 ||
10118 memcmp(rsptr, pp, rslen) == 0)) {
10119 if (at_char_boundary(p, pp, e, enc))
10120 return len - rslen;
10121 RB_GC_GUARD(rs);
10122 }
10123 return len;
10124}
10125
10131static VALUE
10132chomp_rs(int argc, const VALUE *argv)
10133{
10134 rb_check_arity(argc, 0, 1);
10135 if (argc > 0) {
10136 VALUE rs = argv[0];
10137 if (!NIL_P(rs)) StringValue(rs);
10138 return rs;
10139 }
10140 else {
10141 return rb_rs;
10142 }
10143}
10144
10145VALUE
10146rb_str_chomp_string(VALUE str, VALUE rs)
10147{
10148 long olen = RSTRING_LEN(str);
10149 long len = chompped_length(str, rs);
10150 if (len >= olen) return Qnil;
10151 str_modify_keep_cr(str);
10152 STR_SET_LEN(str, len);
10153 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
10154 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
10156 }
10157 return str;
10158}
10159
10160/*
10161 * call-seq:
10162 * chomp!(line_sep = $/) -> self or nil
10163 *
10164 * Like String#chomp, except that:
10165 *
10166 * - Removes trailing characters from +self+ (not from a copy of +self+).
10167 * - Returns +self+ if any characters are removed, +nil+ otherwise.
10168 *
10169 * Related: see {Modifying}[rdoc-ref:String@Modifying].
10170 */
10171
10172static VALUE
10173rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
10174{
10175 VALUE rs;
10176 str_modifiable(str);
10177 if (RSTRING_LEN(str) == 0 && argc < 2) return Qnil;
10178 rs = chomp_rs(argc, argv);
10179 if (NIL_P(rs)) return Qnil;
10180 return rb_str_chomp_string(str, rs);
10181}
10182
10183
10184/*
10185 * call-seq:
10186 * chomp(line_sep = $/) -> new_string
10187 *
10188 * :include: doc/string/chomp.rdoc
10189 *
10190 */
10191
10192static VALUE
10193rb_str_chomp(int argc, VALUE *argv, VALUE str)
10194{
10195 VALUE rs = chomp_rs(argc, argv);
10196 if (NIL_P(rs)) return str_duplicate(rb_cString, str);
10197 return rb_str_subseq(str, 0, chompped_length(str, rs));
10198}
10199
10200static void
10201tr_setup_table_multi(char table[TR_TABLE_SIZE], VALUE *tablep, VALUE *ctablep,
10202 VALUE str, int num_selectors, VALUE *selectors)
10203{
10204 int i;
10205
10206 for (i=0; i<num_selectors; i++) {
10207 VALUE selector = selectors[i];
10208 rb_encoding *enc;
10209
10210 StringValue(selector);
10211 enc = rb_enc_check(str, selector);
10212 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
10213 }
10214}
10215
10216static long
10217lstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
10218{
10219 const char *const start = s;
10220
10221 if (!s || s >= e) return 0;
10222
10223 /* remove spaces at head */
10224 if (single_byte_optimizable(str)) {
10225 while (s < e && (*s == '\0' || ascii_isspace(*s))) s++;
10226 }
10227 else {
10228 while (s < e) {
10229 int n;
10230 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
10231
10232 if (cc && !rb_isspace(cc)) break;
10233 s += n;
10234 }
10235 }
10236 return s - start;
10237}
10238
10239static long
10240lstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
10241 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
10242{
10243 const char *const start = s;
10244
10245 if (!s || s >= e) return 0;
10246
10247 /* remove leading characters in the table */
10248 while (s < e) {
10249 int n;
10250 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
10251
10252 if (!tr_find(cc, table, del, nodel)) break;
10253 s += n;
10254 }
10255 return s - start;
10256}
10257
10258/*
10259 * call-seq:
10260 * lstrip!(*selectors) -> self or nil
10261 *
10262 * Like String#lstrip, except that:
10263 *
10264 * - Performs stripping in +self+ (not in a copy of +self+).
10265 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
10266 *
10267 * Related: see {Modifying}[rdoc-ref:String@Modifying].
10268 */
10269
10270static VALUE
10271rb_str_lstrip_bang(int argc, VALUE *argv, VALUE str)
10272{
10273 rb_encoding *enc;
10274 char *start, *s;
10275 long olen, loffset;
10276
10277 str_modify_keep_cr(str);
10278 enc = STR_ENC_GET(str);
10279 RSTRING_GETMEM(str, start, olen);
10280 if (argc > 0) {
10281 char table[TR_TABLE_SIZE];
10282 VALUE del = 0, nodel = 0;
10283
10284 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
10285 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
10286 }
10287 else {
10288 loffset = lstrip_offset(str, start, start+olen, enc);
10289 }
10290
10291 if (loffset > 0) {
10292 long len = olen-loffset;
10293 s = start + loffset;
10294 memmove(start, s, len);
10295 STR_SET_LEN(str, len);
10296 TERM_FILL(start+len, rb_enc_mbminlen(enc));
10297 return str;
10298 }
10299 return Qnil;
10300}
10301
10302
10303/*
10304 * call-seq:
10305 * lstrip(*selectors) -> new_string
10306 *
10307 * Returns a copy of +self+ with leading whitespace removed;
10308 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
10309 *
10310 * whitespace = "\x00\t\n\v\f\r "
10311 * s = whitespace + 'abc' + whitespace
10312 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
10313 * s.lstrip
10314 * # => "abc\u0000\t\n\v\f\r "
10315 *
10316 * If +selectors+ are given, removes characters of +selectors+ from the beginning of +self+:
10317 *
10318 * s = "---abc+++"
10319 * s.lstrip("-") # => "abc+++"
10320 *
10321 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
10322 * and may use any of its valid forms, including negation, ranges, and escapes:
10323 *
10324 * "01234abc56789".lstrip("0-9") # "abc56789"
10325 * "01234abc56789".lstrip("0-9", "^4-6") # "4abc56789"
10326 *
10327 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10328 */
10329
10330static VALUE
10331rb_str_lstrip(int argc, VALUE *argv, VALUE str)
10332{
10333 char *start;
10334 long len, loffset;
10335
10336 RSTRING_GETMEM(str, start, len);
10337 if (argc > 0) {
10338 char table[TR_TABLE_SIZE];
10339 VALUE del = 0, nodel = 0;
10340
10341 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
10342 loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel);
10343 }
10344 else {
10345 loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
10346 }
10347 if (loffset <= 0) return str_duplicate(rb_cString, str);
10348 return rb_str_subseq(str, loffset, len - loffset);
10349}
10350
10351static long
10352rstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
10353{
10354 const char *t;
10355
10356 rb_str_check_dummy_enc(enc);
10358 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
10359 }
10360 if (!s || s >= e) return 0;
10361 t = e;
10362
10363 /* remove trailing spaces or '\0's */
10364 if (single_byte_optimizable(str)) {
10365 unsigned char c;
10366 while (s < t && ((c = *(t-1)) == '\0' || ascii_isspace(c))) t--;
10367 }
10368 else {
10369 char *tp;
10370
10371 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
10372 unsigned int c = rb_enc_codepoint(tp, e, enc);
10373 if (c && !rb_isspace(c)) break;
10374 t = tp;
10375 }
10376 }
10377 return e - t;
10378}
10379
10380static long
10381rstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
10382 char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
10383{
10384 const char *t;
10385 char *tp;
10386
10387 rb_str_check_dummy_enc(enc);
10389 rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
10390 }
10391 if (!s || s >= e) return 0;
10392 t = e;
10393
10394 /* remove trailing characters in the table */
10395 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
10396 unsigned int c = rb_enc_codepoint(tp, e, enc);
10397 if (!tr_find(c, table, del, nodel)) break;
10398 t = tp;
10399 }
10400
10401 return e - t;
10402}
10403
10404/*
10405 * call-seq:
10406 * rstrip!(*selectors) -> self or nil
10407 *
10408 * Like String#rstrip, except that:
10409 *
10410 * - Performs stripping in +self+ (not in a copy of +self+).
10411 * - Returns +self+ if any characters are stripped, +nil+ otherwise.
10412 *
10413 * Related: see {Modifying}[rdoc-ref:String@Modifying].
10414 */
10415
10416static VALUE
10417rb_str_rstrip_bang(int argc, VALUE *argv, VALUE str)
10418{
10419 rb_encoding *enc;
10420 char *start;
10421 long olen, roffset;
10422
10423 str_modify_keep_cr(str);
10424 enc = STR_ENC_GET(str);
10425 RSTRING_GETMEM(str, start, olen);
10426 if (argc > 0) {
10427 char table[TR_TABLE_SIZE];
10428 VALUE del = 0, nodel = 0;
10429
10430 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
10431 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
10432 }
10433 else {
10434 roffset = rstrip_offset(str, start, start+olen, enc);
10435 }
10436 if (roffset > 0) {
10437 long len = olen - roffset;
10438
10439 STR_SET_LEN(str, len);
10440 TERM_FILL(start+len, rb_enc_mbminlen(enc));
10441 return str;
10442 }
10443 return Qnil;
10444}
10445
10446
10447/*
10448 * call-seq:
10449 * rstrip(*selectors) -> new_string
10450 *
10451 * Returns a copy of +self+ with trailing whitespace removed;
10452 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
10453 *
10454 * whitespace = "\x00\t\n\v\f\r "
10455 * s = whitespace + 'abc' + whitespace
10456 * s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
10457 * s.rstrip # => "\u0000\t\n\v\f\r abc"
10458 *
10459 * If +selectors+ are given, removes characters of +selectors+ from the end of +self+:
10460 *
10461 * s = "---abc+++"
10462 * s.rstrip("+") # => "---abc"
10463 *
10464 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
10465 * and may use any of its valid forms, including negation, ranges, and escapes:
10466 *
10467 * "01234abc56789".rstrip("0-9") # "01234abc"
10468 * "01234abc56789".rstrip("0-9", "^4-6") # "01234abc56"
10469 *
10470 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10471 */
10472
10473static VALUE
10474rb_str_rstrip(int argc, VALUE *argv, VALUE str)
10475{
10476 rb_encoding *enc;
10477 char *start;
10478 long olen, roffset;
10479
10480 enc = STR_ENC_GET(str);
10481 RSTRING_GETMEM(str, start, olen);
10482 if (argc > 0) {
10483 char table[TR_TABLE_SIZE];
10484 VALUE del = 0, nodel = 0;
10485
10486 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
10487 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
10488 }
10489 else {
10490 roffset = rstrip_offset(str, start, start+olen, enc);
10491 }
10492 if (roffset <= 0) return str_duplicate(rb_cString, str);
10493 return rb_str_subseq(str, 0, olen-roffset);
10494}
10495
10496
10497/*
10498 * call-seq:
10499 * strip!(*selectors) -> self or nil
10500 *
10501 * Like String#strip, except that:
10502 *
10503 * - Any modifications are made to +self+.
10504 * - Returns +self+ if any modification are made, +nil+ otherwise.
10505 *
10506 * Related: see {Modifying}[rdoc-ref:String@Modifying].
10507 */
10508
10509static VALUE
10510rb_str_strip_bang(int argc, VALUE *argv, VALUE str)
10511{
10512 char *start;
10513 long olen, loffset, roffset;
10514 rb_encoding *enc;
10515
10516 str_modify_keep_cr(str);
10517 enc = STR_ENC_GET(str);
10518 RSTRING_GETMEM(str, start, olen);
10519
10520 if (argc > 0) {
10521 char table[TR_TABLE_SIZE];
10522 VALUE del = 0, nodel = 0;
10523
10524 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
10525 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
10526 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
10527 }
10528 else {
10529 loffset = lstrip_offset(str, start, start+olen, enc);
10530 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
10531 }
10532
10533 if (loffset > 0 || roffset > 0) {
10534 long len = olen-roffset;
10535 if (loffset > 0) {
10536 len -= loffset;
10537 memmove(start, start + loffset, len);
10538 }
10539 STR_SET_LEN(str, len);
10540 TERM_FILL(start+len, rb_enc_mbminlen(enc));
10541 return str;
10542 }
10543 return Qnil;
10544}
10545
10546
10547/*
10548 * call-seq:
10549 * strip(*selectors) -> new_string
10550 *
10551 * Returns a copy of +self+ with leading and trailing whitespace removed;
10552 * see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
10553 *
10554 * whitespace = "\x00\t\n\v\f\r "
10555 * s = whitespace + 'abc' + whitespace
10556 * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
10557 * s.strip # => "abc"
10558 *
10559 * If +selectors+ are given, removes characters of +selectors+ from both ends of +self+:
10560 *
10561 * s = "---abc+++"
10562 * s.strip("-+") # => "abc"
10563 * s.strip("+-") # => "abc"
10564 *
10565 * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
10566 * and may use any of its valid forms, including negation, ranges, and escapes:
10567 *
10568 * "01234abc56789".strip("0-9") # "abc"
10569 * "01234abc56789".strip("0-9", "^4-6") # "4abc56"
10570 *
10571 * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
10572 */
10573
10574static VALUE
10575rb_str_strip(int argc, VALUE *argv, VALUE str)
10576{
10577 char *start;
10578 long olen, loffset, roffset;
10579 rb_encoding *enc = STR_ENC_GET(str);
10580
10581 RSTRING_GETMEM(str, start, olen);
10582
10583 if (argc > 0) {
10584 char table[TR_TABLE_SIZE];
10585 VALUE del = 0, nodel = 0;
10586
10587 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
10588 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
10589 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
10590 }
10591 else {
10592 loffset = lstrip_offset(str, start, start+olen, enc);
10593 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
10594 }
10595
10596 if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
10597 return rb_str_subseq(str, loffset, olen-loffset-roffset);
10598}
10599
10600static VALUE
10601scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
10602{
10603 VALUE result = Qnil;
10604 long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
10605 if (pos >= 0) {
10606 VALUE match;
10607 struct re_registers *regs;
10608 if (BUILTIN_TYPE(pat) == T_STRING) {
10609 regs = NULL;
10610 end = pos + RSTRING_LEN(pat);
10611 }
10612 else {
10613 match = rb_backref_get();
10614 regs = RMATCH_REGS(match);
10615 pos = BEG(0);
10616 end = END(0);
10617 }
10618
10619 if (pos == end) {
10620 rb_encoding *enc = STR_ENC_GET(str);
10621 /*
10622 * Always consume at least one character of the input string
10623 */
10624 if (RSTRING_LEN(str) > end)
10625 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
10626 RSTRING_END(str), enc);
10627 else
10628 *start = end + 1;
10629 }
10630 else {
10631 *start = end;
10632 }
10633
10634 if (!regs || regs->num_regs == 1) {
10635 result = rb_str_subseq(str, pos, end - pos);
10636 return result;
10637 }
10638 else {
10639 result = rb_ary_new2(regs->num_regs);
10640 for (int i = 1; i < regs->num_regs; i++) {
10641 VALUE s = Qnil;
10642 if (BEG(i) >= 0) {
10643 s = rb_str_subseq(str, BEG(i), END(i)-BEG(i));
10644 }
10645
10646 rb_ary_push(result, s);
10647 }
10648 }
10649
10650 RB_GC_GUARD(match);
10651 }
10652
10653 return result;
10654}
10655
10656
10657/*
10658 * call-seq:
10659 * scan(pattern) -> array_of_results
10660 * scan(pattern) {|result| ... } -> self
10661 *
10662 * :include: doc/string/scan.rdoc
10663 *
10664 */
10665
10666static VALUE
10667rb_str_scan(VALUE str, VALUE pat)
10668{
10669 VALUE result;
10670 long start = 0;
10671 long last = -1, prev = 0;
10672 char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);
10673
10674 pat = get_pat_quoted(pat, 1);
10675 mustnot_broken(str);
10676 if (!rb_block_given_p()) {
10677 VALUE ary = rb_ary_new();
10678
10679 while (!NIL_P(result = scan_once(str, pat, &start, 0))) {
10680 last = prev;
10681 prev = start;
10682 rb_ary_push(ary, result);
10683 }
10684 if (last >= 0) rb_pat_search(pat, str, last, 1);
10685 else rb_backref_set(Qnil);
10686 return ary;
10687 }
10688
10689 while (!NIL_P(result = scan_once(str, pat, &start, 1))) {
10690 last = prev;
10691 prev = start;
10692 rb_yield(result);
10693 str_mod_check(str, p, len);
10694 }
10695 if (last >= 0) rb_pat_search(pat, str, last, 1);
10696 return str;
10697}
10698
10699
10700/*
10701 * call-seq:
10702 * hex -> integer
10703 *
10704 * Interprets the leading substring of +self+ as hexadecimal, possibly signed;
10705 * returns its value as an integer.
10706 *
10707 * The leading substring is interpreted as hexadecimal when it begins with:
10708 *
10709 * - One or more character representing hexadecimal digits
10710 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
10711 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit:
10712 *
10713 * 'f'.hex # => 15
10714 * '11'.hex # => 17
10715 * 'FFF'.hex # => 4095
10716 * 'fffg'.hex # => 4095
10717 * 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not.
10718 * 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not.
10719 * 'deadbeef'.hex # => 3735928559
10720 *
10721 * - <tt>'0x'</tt> or <tt>'0X'</tt>, followed by one or more hexadecimal digits:
10722 *
10723 * '0xfff'.hex # => 4095
10724 * '0xfffg'.hex # => 4095
10725 *
10726 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
10727 *
10728 * '-fff'.hex # => -4095
10729 * '-0xFFF'.hex # => -4095
10730 *
10731 * For any substring not described above, returns zero:
10732 *
10733 * 'xxx'.hex # => 0
10734 * ''.hex # => 0
10735 *
10736 * Note that, unlike #oct, this method interprets only hexadecimal,
10737 * and not binary, octal, or decimal notations:
10738 *
10739 * '0b111'.hex # => 45329
10740 * '0o777'.hex # => 0
10741 * '0d999'.hex # => 55705
10742 *
10743 * Related: See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
10744 */
10745
10746static VALUE
10747rb_str_hex(VALUE str)
10748{
10749 return rb_str_to_inum(str, 16, FALSE);
10750}
10751
10752
10753/*
10754 * call-seq:
10755 * oct -> integer
10756 *
10757 * Interprets the leading substring of +self+ as octal, binary, decimal, or hexadecimal, possibly signed;
10758 * returns their value as an integer.
10759 *
10760 * In brief:
10761 *
10762 * # Interpreted as octal.
10763 * '777'.oct # => 511
10764 * '777x'.oct # => 511
10765 * '0777'.oct # => 511
10766 * '0o777'.oct # => 511
10767 * '-777'.oct # => -511
10768 * # Not interpreted as octal.
10769 * '0b111'.oct # => 7 # Interpreted as binary.
10770 * '0d999'.oct # => 999 # Interpreted as decimal.
10771 * '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
10772 *
10773 * The leading substring is interpreted as octal when it begins with:
10774 *
10775 * - One or more character representing octal digits
10776 * (each in the range <tt>'0'..'7'</tt>);
10777 * the string to be interpreted ends at the first character that does not represent an octal digit:
10778 *
10779 * '7'.oct @ => 7
10780 * '11'.oct # => 9
10781 * '777'.oct # => 511
10782 * '0777'.oct # => 511
10783 * '7778'.oct # => 511
10784 * '777x'.oct # => 511
10785 *
10786 * - <tt>'0o'</tt>, followed by one or more octal digits:
10787 *
10788 * '0o777'.oct # => 511
10789 * '0o7778'.oct # => 511
10790 *
10791 * The leading substring is _not_ interpreted as octal when it begins with:
10792 *
10793 * - <tt>'0b'</tt>, followed by one or more characters representing binary digits
10794 * (each in the range <tt>'0'..'1'</tt>);
10795 * the string to be interpreted ends at the first character that does not represent a binary digit.
10796 * the string is interpreted as binary digits (base 2):
10797 *
10798 * '0b111'.oct # => 7
10799 * '0b1112'.oct # => 7
10800 *
10801 * - <tt>'0d'</tt>, followed by one or more characters representing decimal digits
10802 * (each in the range <tt>'0'..'9'</tt>);
10803 * the string to be interpreted ends at the first character that does not represent a decimal digit.
10804 * the string is interpreted as decimal digits (base 10):
10805 *
10806 * '0d999'.oct # => 999
10807 * '0d999x'.oct # => 999
10808 *
10809 * - <tt>'0x'</tt>, followed by one or more characters representing hexadecimal digits
10810 * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
10811 * the string to be interpreted ends at the first character that does not represent a hexadecimal digit.
10812 * the string is interpreted as hexadecimal digits (base 16):
10813 *
10814 * '0xfff'.oct # => 4095
10815 * '0xfffg'.oct # => 4095
10816 *
10817 * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
10818 *
10819 * '-777'.oct # => -511
10820 * '-0777'.oct # => -511
10821 * '-0b111'.oct # => -7
10822 * '-0xfff'.oct # => -4095
10823 *
10824 * For any substring not described above, returns zero:
10825 *
10826 * 'foo'.oct # => 0
10827 * ''.oct # => 0
10828 *
10829 * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
10830 */
10831
10832static VALUE
10833rb_str_oct(VALUE str)
10834{
10835 return rb_str_to_inum(str, -8, FALSE);
10836}
10837
10838#ifndef HAVE_CRYPT_R
10839# include "ruby/thread_native.h"
10840# include "ruby/atomic.h"
10841
10842static struct {
10843 rb_nativethread_lock_t lock;
10844} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
10845#endif
10846
10847/*
10848 * call-seq:
10849 * crypt(salt_str) -> new_string
10850 *
10851 * Returns the string generated by calling <code>crypt(3)</code>
10852 * standard library function with <code>str</code> and
10853 * <code>salt_str</code>, in this order, as its arguments. Please do
10854 * not use this method any longer. It is legacy; provided only for
10855 * backward compatibility with ruby scripts in earlier days. It is
10856 * bad to use in contemporary programs for several reasons:
10857 *
10858 * * Behaviour of C's <code>crypt(3)</code> depends on the OS it is
10859 * run. The generated string lacks data portability.
10860 *
10861 * * On some OSes such as Mac OS, <code>crypt(3)</code> never fails
10862 * (i.e. silently ends up in unexpected results).
10863 *
10864 * * On some OSes such as Mac OS, <code>crypt(3)</code> is not
10865 * thread safe.
10866 *
10867 * * So-called "traditional" usage of <code>crypt(3)</code> is very
10868 * very very weak. According to its manpage, Linux's traditional
10869 * <code>crypt(3)</code> output has only 2**56 variations; too
10870 * easy to brute force today. And this is the default behaviour.
10871 *
10872 * * In order to make things robust some OSes implement so-called
10873 * "modular" usage. To go through, you have to do a complex
10874 * build-up of the <code>salt_str</code> parameter, by hand.
10875 * Failure in generation of a proper salt string tends not to
10876 * yield any errors; typos in parameters are normally not
10877 * detectable.
10878 *
10879 * * For instance, in the following example, the second invocation
10880 * of String#crypt is wrong; it has a typo in "round=" (lacks
10881 * "s"). However the call does not fail and something unexpected
10882 * is generated.
10883 *
10884 * "foo".crypt("$5$rounds=1000$salt$") # OK, proper usage
10885 * "foo".crypt("$5$round=1000$salt$") # Typo not detected
10886 *
10887 * * Even in the "modular" mode, some hash functions are considered
10888 * archaic and no longer recommended at all; for instance module
10889 * <code>$1$</code> is officially abandoned by its author: see
10890 * http://phk.freebsd.dk/sagas/md5crypt_eol/ . For another
10891 * instance module <code>$3$</code> is considered completely
10892 * broken: see the manpage of FreeBSD.
10893 *
10894 * * On some OS such as Mac OS, there is no modular mode. Yet, as
10895 * written above, <code>crypt(3)</code> on Mac OS never fails.
10896 * This means even if you build up a proper salt string it
10897 * generates a traditional DES hash anyways, and there is no way
10898 * for you to be aware of.
10899 *
10900 * "foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
10901 *
10902 * If for some reason you cannot migrate to other secure contemporary
10903 * password hashing algorithms, install the string-crypt gem and
10904 * <code>require 'string/crypt'</code> to continue using it.
10905 */
10906
10907static VALUE
10908rb_str_crypt(VALUE str, VALUE salt)
10909{
10910#ifdef HAVE_CRYPT_R
10911 VALUE databuf;
10912 struct crypt_data *data;
10913# define CRYPT_END() ALLOCV_END(databuf)
10914#else
10915 char *tmp_buf;
10916 extern char *crypt(const char *, const char *);
10917# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
10918#endif
10919 VALUE result;
10920 const char *s, *saltp;
10921 char *res;
10922#ifdef BROKEN_CRYPT
10923 char salt_8bit_clean[3];
10924#endif
10925
10926 StringValue(salt);
10927 mustnot_wchar(str);
10928 mustnot_wchar(salt);
10929 s = StringValueCStr(str);
10930 saltp = RSTRING_PTR(salt);
10931 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
10932 rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
10933 }
10934
10935#ifdef BROKEN_CRYPT
10936 if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) {
10937 salt_8bit_clean[0] = saltp[0] & 0x7f;
10938 salt_8bit_clean[1] = saltp[1] & 0x7f;
10939 salt_8bit_clean[2] = '\0';
10940 saltp = salt_8bit_clean;
10941 }
10942#endif
10943#ifdef HAVE_CRYPT_R
10944 data = ALLOCV(databuf, sizeof(struct crypt_data));
10945# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
10946 data->initialized = 0;
10947# endif
10948 res = crypt_r(s, saltp, data);
10949#else
10950 rb_nativethread_lock_lock(&crypt_mutex.lock);
10951 res = crypt(s, saltp);
10952#endif
10953 if (!res) {
10954 int err = errno;
10955 CRYPT_END();
10956 rb_syserr_fail(err, "crypt");
10957 }
10958#ifdef HAVE_CRYPT_R
10959 result = rb_str_new_cstr(res);
10960 CRYPT_END();
10961#else
10962 // We need to copy this buffer because it's static and we need to unlock the mutex
10963 // before allocating a new object (the string to be returned). If we allocate while
10964 // holding the lock, we could run GC which fires the VM barrier and causes a deadlock
10965 // if other ractors are waiting on this lock.
10966 size_t res_size = strlen(res)+1;
10967 tmp_buf = ALLOCA_N(char, res_size); // should be small enough to alloca
10968 memcpy(tmp_buf, res, res_size);
10969 res = tmp_buf;
10970 CRYPT_END();
10971 result = rb_str_new_cstr(res);
10972#endif
10973 return result;
10974}
10975
10976
10977/*
10978 * call-seq:
10979 * ord -> integer
10980 *
10981 * :include: doc/string/ord.rdoc
10982 *
10983 */
10984
10985static VALUE
10986rb_str_ord(VALUE s)
10987{
10988 unsigned int c;
10989
10990 c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
10991 return UINT2NUM(c);
10992}
10993/*
10994 * call-seq:
10995 * sum(n = 16) -> integer
10996 *
10997 * :include: doc/string/sum.rdoc
10998 *
10999 */
11000
11001static VALUE
11002rb_str_sum(int argc, VALUE *argv, VALUE str)
11003{
11004 int bits = 16;
11005 char *ptr, *p, *pend;
11006 long len;
11007 VALUE sum = INT2FIX(0);
11008 unsigned long sum0 = 0;
11009
11010 if (rb_check_arity(argc, 0, 1) && (bits = NUM2INT(argv[0])) < 0) {
11011 bits = 0;
11012 }
11013 ptr = p = RSTRING_PTR(str);
11014 len = RSTRING_LEN(str);
11015 pend = p + len;
11016
11017 while (p < pend) {
11018 if (FIXNUM_MAX - UCHAR_MAX < sum0) {
11019 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
11020 str_mod_check(str, ptr, len);
11021 sum0 = 0;
11022 }
11023 sum0 += (unsigned char)*p;
11024 p++;
11025 }
11026
11027 if (bits == 0) {
11028 if (sum0) {
11029 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
11030 }
11031 }
11032 else {
11033 if (sum == INT2FIX(0)) {
11034 if (bits < (int)sizeof(long)*CHAR_BIT) {
11035 sum0 &= (((unsigned long)1)<<bits)-1;
11036 }
11037 sum = LONG2FIX(sum0);
11038 }
11039 else {
11040 VALUE mod;
11041
11042 if (sum0) {
11043 sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
11044 }
11045
11046 mod = rb_funcall(INT2FIX(1), idLTLT, 1, INT2FIX(bits));
11047 mod = rb_funcall(mod, '-', 1, INT2FIX(1));
11048 sum = rb_funcall(sum, '&', 1, mod);
11049 }
11050 }
11051 return sum;
11052}
11053
11054static VALUE
11055rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
11056{
11057 rb_encoding *enc;
11058 VALUE w;
11059 long width, len, flen = 1, fclen = 1;
11060 VALUE res;
11061 char *p;
11062 const char *f = " ";
11063 long n, size, llen, rlen, llen2 = 0, rlen2 = 0;
11064 VALUE pad;
11065 int singlebyte = 1, cr;
11066 int termlen;
11067
11068 rb_scan_args(argc, argv, "11", &w, &pad);
11069 enc = STR_ENC_GET(str);
11070 termlen = rb_enc_mbminlen(enc);
11071 width = NUM2LONG(w);
11072 if (argc == 2) {
11073 StringValue(pad);
11074 enc = rb_enc_check(str, pad);
11075 f = RSTRING_PTR(pad);
11076 flen = RSTRING_LEN(pad);
11077 fclen = str_strlen(pad, enc); /* rb_enc_check */
11078 singlebyte = single_byte_optimizable(pad);
11079 if (flen == 0 || fclen == 0) {
11080 rb_raise(rb_eArgError, "zero width padding");
11081 }
11082 }
11083 len = str_strlen(str, enc); /* rb_enc_check */
11084 if (width < 0 || len >= width) return str_duplicate(rb_cString, str);
11085 n = width - len;
11086 llen = (jflag == 'l') ? 0 : ((jflag == 'r') ? n : n/2);
11087 rlen = n - llen;
11088 cr = ENC_CODERANGE(str);
11089 if (flen > 1) {
11090 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
11091 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
11092 }
11093 size = RSTRING_LEN(str);
11094 if ((len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
11095 (len *= flen) >= LONG_MAX - llen2 - rlen2 ||
11096 (len += llen2 + rlen2) >= LONG_MAX - size) {
11097 rb_raise(rb_eArgError, "argument too big");
11098 }
11099 len += size;
11100 res = str_enc_new(rb_cString, 0, len, enc);
11101 p = RSTRING_PTR(res);
11102 if (flen <= 1) {
11103 memset(p, *f, llen);
11104 p += llen;
11105 }
11106 else {
11107 while (llen >= fclen) {
11108 memcpy(p,f,flen);
11109 p += flen;
11110 llen -= fclen;
11111 }
11112 if (llen > 0) {
11113 memcpy(p, f, llen2);
11114 p += llen2;
11115 }
11116 }
11117 memcpy(p, RSTRING_PTR(str), size);
11118 p += size;
11119 if (flen <= 1) {
11120 memset(p, *f, rlen);
11121 p += rlen;
11122 }
11123 else {
11124 while (rlen >= fclen) {
11125 memcpy(p,f,flen);
11126 p += flen;
11127 rlen -= fclen;
11128 }
11129 if (rlen > 0) {
11130 memcpy(p, f, rlen2);
11131 p += rlen2;
11132 }
11133 }
11134 TERM_FILL(p, termlen);
11135 STR_SET_LEN(res, p-RSTRING_PTR(res));
11136
11137 if (argc == 2)
11138 cr = ENC_CODERANGE_AND(cr, ENC_CODERANGE(pad));
11139 if (cr != ENC_CODERANGE_BROKEN)
11140 ENC_CODERANGE_SET(res, cr);
11141
11142 RB_GC_GUARD(pad);
11143 return res;
11144}
11145
11146
11147/*
11148 * call-seq:
11149 * ljust(width, pad_string = ' ') -> new_string
11150 *
11151 * :include: doc/string/ljust.rdoc
11152 *
11153 */
11154
11155static VALUE
11156rb_str_ljust(int argc, VALUE *argv, VALUE str)
11157{
11158 return rb_str_justify(argc, argv, str, 'l');
11159}
11160
11161/*
11162 * call-seq:
11163 * rjust(width, pad_string = ' ') -> new_string
11164 *
11165 * :include: doc/string/rjust.rdoc
11166 *
11167 */
11168
11169static VALUE
11170rb_str_rjust(int argc, VALUE *argv, VALUE str)
11171{
11172 return rb_str_justify(argc, argv, str, 'r');
11173}
11174
11175
11176/*
11177 * call-seq:
11178 * center(size, pad_string = ' ') -> new_string
11179 *
11180 * :include: doc/string/center.rdoc
11181 *
11182 */
11183
11184static VALUE
11185rb_str_center(int argc, VALUE *argv, VALUE str)
11186{
11187 return rb_str_justify(argc, argv, str, 'c');
11188}
11189
11190/*
11191 * call-seq:
11192 * partition(pattern) -> [pre_match, first_match, post_match]
11193 *
11194 * :include: doc/string/partition.rdoc
11195 *
11196 */
11197
11198static VALUE
11199rb_str_partition(VALUE str, VALUE sep)
11200{
11201 long pos;
11202
11203 sep = get_pat_quoted(sep, 0);
11204 if (RB_TYPE_P(sep, T_REGEXP)) {
11205 if (rb_reg_search(sep, str, 0, 0) < 0) {
11206 goto failed;
11207 }
11208 VALUE match = rb_backref_get();
11209 struct re_registers *regs = RMATCH_REGS(match);
11210
11211 pos = BEG(0);
11212 sep = rb_str_subseq(str, pos, END(0) - pos);
11213 }
11214 else {
11215 pos = rb_str_index(str, sep, 0);
11216 if (pos < 0) goto failed;
11217 }
11218 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
11219 sep,
11220 rb_str_subseq(str, pos+RSTRING_LEN(sep),
11221 RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
11222
11223 failed:
11224 return rb_ary_new3(3, str_duplicate(rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
11225}
11226
11227/*
11228 * call-seq:
11229 * rpartition(pattern) -> [pre_match, last_match, post_match]
11230 *
11231 * :include: doc/string/rpartition.rdoc
11232 *
11233 */
11234
11235static VALUE
11236rb_str_rpartition(VALUE str, VALUE sep)
11237{
11238 long pos = RSTRING_LEN(str);
11239
11240 sep = get_pat_quoted(sep, 0);
11241 if (RB_TYPE_P(sep, T_REGEXP)) {
11242 if (rb_reg_search(sep, str, pos, 1) < 0) {
11243 goto failed;
11244 }
11245 VALUE match = rb_backref_get();
11246 struct re_registers *regs = RMATCH_REGS(match);
11247
11248 pos = BEG(0);
11249 sep = rb_str_subseq(str, pos, END(0) - pos);
11250 }
11251 else {
11252 pos = rb_str_sublen(str, pos);
11253 pos = rb_str_rindex(str, sep, pos);
11254 if (pos < 0) {
11255 goto failed;
11256 }
11257 }
11258
11259 return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
11260 sep,
11261 rb_str_subseq(str, pos+RSTRING_LEN(sep),
11262 RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
11263 failed:
11264 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(rb_cString, str));
11265}
11266
11267/*
11268 * call-seq:
11269 * start_with?(*patterns) -> true or false
11270 *
11271 * :include: doc/string/start_with_p.rdoc
11272 *
11273 */
11274
11275static VALUE
11276rb_str_start_with(int argc, VALUE *argv, VALUE str)
11277{
11278 int i;
11279
11280 for (i=0; i<argc; i++) {
11281 VALUE tmp = argv[i];
11282 if (RB_TYPE_P(tmp, T_REGEXP)) {
11283 if (rb_reg_start_with_p(tmp, str))
11284 return Qtrue;
11285 }
11286 else {
11287 const char *p, *s, *e;
11288 long slen, tlen;
11289 rb_encoding *enc;
11290
11291 StringValue(tmp);
11292 enc = rb_enc_check(str, tmp);
11293 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
11294 if ((slen = RSTRING_LEN(str)) < tlen) continue;
11295 p = RSTRING_PTR(str);
11296 e = p + slen;
11297 s = p + tlen;
11298 if (!at_char_right_boundary(p, s, e, enc))
11299 continue;
11300 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
11301 return Qtrue;
11302 }
11303 }
11304 return Qfalse;
11305}
11306
11307/*
11308 * call-seq:
11309 * end_with?(*strings) -> true or false
11310 *
11311 * :include: doc/string/end_with_p.rdoc
11312 *
11313 */
11314
11315static VALUE
11316rb_str_end_with(int argc, VALUE *argv, VALUE str)
11317{
11318 int i;
11319
11320 for (i=0; i<argc; i++) {
11321 VALUE tmp = argv[i];
11322 const char *p, *s, *e;
11323 long slen, tlen;
11324 rb_encoding *enc;
11325
11326 StringValue(tmp);
11327 enc = rb_enc_check(str, tmp);
11328 if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
11329 if ((slen = RSTRING_LEN(str)) < tlen) continue;
11330 p = RSTRING_PTR(str);
11331 e = p + slen;
11332 s = e - tlen;
11333 if (!at_char_boundary(p, s, e, enc))
11334 continue;
11335 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
11336 return Qtrue;
11337 }
11338 return Qfalse;
11339}
11340
11350static long
11351deleted_prefix_length(VALUE str, VALUE prefix)
11352{
11353 const char *strptr, *prefixptr;
11354 long olen, prefixlen;
11355 rb_encoding *enc = rb_enc_get(str);
11356
11357 StringValue(prefix);
11358
11359 if (!is_broken_string(prefix) ||
11360 !rb_enc_asciicompat(enc) ||
11361 !rb_enc_asciicompat(rb_enc_get(prefix))) {
11362 enc = rb_enc_check(str, prefix);
11363 }
11364
11365 /* return 0 if not start with prefix */
11366 prefixlen = RSTRING_LEN(prefix);
11367 if (prefixlen <= 0) return 0;
11368 olen = RSTRING_LEN(str);
11369 if (olen < prefixlen) return 0;
11370 strptr = RSTRING_PTR(str);
11371 prefixptr = RSTRING_PTR(prefix);
11372 if (memcmp(strptr, prefixptr, prefixlen) != 0) return 0;
11373 if (is_broken_string(prefix)) {
11374 if (!is_broken_string(str)) {
11375 /* prefix in a valid string cannot be broken */
11376 return 0;
11377 }
11378 const char *strend = strptr + olen;
11379 const char *after_prefix = strptr + prefixlen;
11380 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
11381 /* prefix does not end at char-boundary */
11382 return 0;
11383 }
11384 }
11385 /* prefix part in `str` also should be valid. */
11386
11387 return prefixlen;
11388}
11389
11390/*
11391 * call-seq:
11392 * delete_prefix!(prefix) -> self or nil
11393 *
11394 * Like String#delete_prefix, except that +self+ is modified in place;
11395 * returns +self+ if the prefix is removed, +nil+ otherwise.
11396 *
11397 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11398 */
11399
11400static VALUE
11401rb_str_delete_prefix_bang(VALUE str, VALUE prefix)
11402{
11403 long prefixlen;
11404 str_modify_keep_cr(str);
11405
11406 prefixlen = deleted_prefix_length(str, prefix);
11407 if (prefixlen <= 0) return Qnil;
11408
11409 return rb_str_drop_bytes(str, prefixlen);
11410}
11411
11412/*
11413 * call-seq:
11414 * delete_prefix(prefix) -> new_string
11415 *
11416 * :include: doc/string/delete_prefix.rdoc
11417 *
11418 */
11419
11420static VALUE
11421rb_str_delete_prefix(VALUE str, VALUE prefix)
11422{
11423 long prefixlen;
11424
11425 prefixlen = deleted_prefix_length(str, prefix);
11426 if (prefixlen <= 0) return str_duplicate(rb_cString, str);
11427
11428 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
11429}
11430
11440static long
11441deleted_suffix_length(VALUE str, VALUE suffix)
11442{
11443 const char *strptr, *suffixptr;
11444 long olen, suffixlen;
11445 rb_encoding *enc;
11446
11447 StringValue(suffix);
11448 if (is_broken_string(suffix)) return 0;
11449 enc = rb_enc_check(str, suffix);
11450
11451 /* return 0 if not start with suffix */
11452 suffixlen = RSTRING_LEN(suffix);
11453 if (suffixlen <= 0) return 0;
11454 olen = RSTRING_LEN(str);
11455 if (olen < suffixlen) return 0;
11456 strptr = RSTRING_PTR(str);
11457 suffixptr = RSTRING_PTR(suffix);
11458 const char *strend = strptr + olen;
11459 const char *before_suffix = strend - suffixlen;
11460 if (memcmp(before_suffix, suffixptr, suffixlen) != 0) return 0;
11461 if (!at_char_boundary(strptr, before_suffix, strend, enc)) return 0;
11462
11463 return suffixlen;
11464}
11465
11466/*
11467 * call-seq:
11468 * delete_suffix!(suffix) -> self or nil
11469 *
11470 * Like String#delete_suffix, except that +self+ is modified in place;
11471 * returns +self+ if the suffix is removed, +nil+ otherwise.
11472 *
11473 * Related: see {Modifying}[rdoc-ref:String@Modifying].
11474 */
11475
11476static VALUE
11477rb_str_delete_suffix_bang(VALUE str, VALUE suffix)
11478{
11479 long olen, suffixlen, len;
11480 str_modifiable(str);
11481
11482 suffixlen = deleted_suffix_length(str, suffix);
11483 if (suffixlen <= 0) return Qnil;
11484
11485 olen = RSTRING_LEN(str);
11486 str_modify_keep_cr(str);
11487 len = olen - suffixlen;
11488 STR_SET_LEN(str, len);
11489 TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
11490 if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
11492 }
11493 return str;
11494}
11495
11496/*
11497 * call-seq:
11498 * delete_suffix(suffix) -> new_string
11499 *
11500 * :include: doc/string/delete_suffix.rdoc
11501 *
11502 */
11503
11504static VALUE
11505rb_str_delete_suffix(VALUE str, VALUE suffix)
11506{
11507 long suffixlen;
11508
11509 suffixlen = deleted_suffix_length(str, suffix);
11510 if (suffixlen <= 0) return str_duplicate(rb_cString, str);
11511
11512 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
11513}
11514
11515void
11516rb_str_setter(VALUE val, ID id, VALUE *var)
11517{
11518 if (!NIL_P(val) && !RB_TYPE_P(val, T_STRING)) {
11519 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
11520 }
11521 *var = val;
11522}
11523
11524static void
11525nil_setter_warning(ID id)
11526{
11527 rb_warn_deprecated("non-nil '%"PRIsVALUE"'", NULL, rb_id2str(id));
11528}
11529
11530void
11531rb_deprecated_str_setter(VALUE val, ID id, VALUE *var)
11532{
11533 rb_str_setter(val, id, var);
11534 if (!NIL_P(*var)) {
11535 nil_setter_warning(id);
11536 }
11537}
11538
11539static void
11540rb_fs_setter(VALUE val, ID id, VALUE *var)
11541{
11542 val = rb_fs_check(val);
11543 if (!val) {
11544 rb_raise(rb_eTypeError,
11545 "value of %"PRIsVALUE" must be String or Regexp",
11546 rb_id2str(id));
11547 }
11548 if (!NIL_P(val)) {
11549 nil_setter_warning(id);
11550 }
11551 *var = val;
11552}
11553
11554
11555/*
11556 * call-seq:
11557 * force_encoding(encoding) -> self
11558 *
11559 * :include: doc/string/force_encoding.rdoc
11560 *
11561 */
11562
11563static VALUE
11564rb_str_force_encoding(VALUE str, VALUE enc)
11565{
11566 str_modifiable(str);
11567
11568 rb_encoding *encoding = rb_to_encoding(enc);
11569 int idx = rb_enc_to_index(encoding);
11570
11571 // If the encoding is unchanged, we do nothing.
11572 if (ENCODING_GET(str) == idx) {
11573 return str;
11574 }
11575
11576 rb_enc_associate_index(str, idx);
11577
11578 // If the coderange was 7bit and the new encoding is ASCII-compatible
11579 // we can keep the coderange.
11580 if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT && encoding && rb_enc_asciicompat(encoding)) {
11581 return str;
11582 }
11583
11585 return str;
11586}
11587
11588/*
11589 * call-seq:
11590 * b -> new_string
11591 *
11592 * :include: doc/string/b.rdoc
11593 *
11594 */
11595
11596static VALUE
11597rb_str_b(VALUE str)
11598{
11599 VALUE str2;
11600 if (STR_EMBED_P(str)) {
11601 str2 = str_alloc_embed(rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
11602 }
11603 else {
11604 str2 = str_alloc_heap(rb_cString);
11605 }
11606 str_replace_shared_without_enc(str2, str);
11607
11608 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
11609 // BINARY strings can never be broken; they're either 7-bit ASCII or VALID.
11610 // If we know the receiver's code range then we know the result's code range.
11611 int cr = ENC_CODERANGE(str);
11612 switch (cr) {
11613 case ENC_CODERANGE_7BIT:
11615 break;
11619 break;
11620 default:
11621 ENC_CODERANGE_CLEAR(str2);
11622 break;
11623 }
11624 }
11625
11626 return str2;
11627}
11628
11629/*
11630 * call-seq:
11631 * valid_encoding? -> true or false
11632 *
11633 * :include: doc/string/valid_encoding_p.rdoc
11634 *
11635 */
11636
11637static VALUE
11638rb_str_valid_encoding_p(VALUE str)
11639{
11640 int cr = rb_enc_str_coderange(str);
11641
11642 return RBOOL(cr != ENC_CODERANGE_BROKEN);
11643}
11644
11645/*
11646 * call-seq:
11647 * ascii_only? -> true or false
11648 *
11649 * Returns whether +self+ contains only ASCII characters:
11650 *
11651 * 'abc'.ascii_only? # => true
11652 * "abc\u{6666}".ascii_only? # => false
11653 *
11654 * Related: see {Querying}[rdoc-ref:String@Querying].
11655 */
11656
11657static VALUE
11658rb_str_is_ascii_only_p(VALUE str)
11659{
11660 int cr = rb_enc_str_coderange(str);
11661
11662 return RBOOL(cr == ENC_CODERANGE_7BIT);
11663}
11664
11665VALUE
11667{
11668 static const char ellipsis[] = "...";
11669 const long ellipsislen = sizeof(ellipsis) - 1;
11670 rb_encoding *const enc = rb_enc_get(str);
11671 const long blen = RSTRING_LEN(str);
11672 const char *const p = RSTRING_PTR(str), *e = p + blen;
11673 VALUE estr, ret = 0;
11674
11675 if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
11676 if (len * rb_enc_mbminlen(enc) >= blen ||
11677 (e = rb_enc_nth(p, e, len, enc)) - p == blen) {
11678 ret = str;
11679 }
11680 else if (len <= ellipsislen ||
11681 !(e = rb_enc_step_back(p, e, e, len = ellipsislen, enc))) {
11682 if (rb_enc_asciicompat(enc)) {
11683 ret = rb_str_new(ellipsis, len);
11684 rb_enc_associate(ret, enc);
11685 }
11686 else {
11687 estr = rb_usascii_str_new(ellipsis, len);
11688 ret = rb_str_encode(estr, rb_enc_from_encoding(enc), 0, Qnil);
11689 }
11690 }
11691 else if (ret = rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
11692 rb_str_cat(ret, ellipsis, ellipsislen);
11693 }
11694 else {
11695 estr = rb_str_encode(rb_usascii_str_new(ellipsis, ellipsislen),
11696 rb_enc_from_encoding(enc), 0, Qnil);
11697 rb_str_append(ret, estr);
11698 }
11699 return ret;
11700}
11701
11702static VALUE
11703str_compat_and_valid(VALUE str, rb_encoding *enc)
11704{
11705 int cr;
11706 str = StringValue(str);
11707 cr = rb_enc_str_coderange(str);
11708 if (cr == ENC_CODERANGE_BROKEN) {
11709 rb_raise(rb_eArgError, "replacement must be valid byte sequence '%+"PRIsVALUE"'", str);
11710 }
11711 else {
11712 rb_encoding *e = STR_ENC_GET(str);
11713 if (cr == ENC_CODERANGE_7BIT ? rb_enc_mbminlen(enc) != 1 : enc != e) {
11714 rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
11715 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
11716 }
11717 }
11718 return str;
11719}
11720
11721static VALUE enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr);
11722
11723VALUE
11725{
11726 rb_encoding *enc = STR_ENC_GET(str);
11727 return enc_str_scrub(enc, str, repl, ENC_CODERANGE(str));
11728}
11729
11730VALUE
11731rb_enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl)
11732{
11733 int cr = ENC_CODERANGE_UNKNOWN;
11734 if (enc == STR_ENC_GET(str)) {
11735 /* cached coderange makes sense only when enc equals the
11736 * actual encoding of str */
11737 cr = ENC_CODERANGE(str);
11738 }
11739 return enc_str_scrub(enc, str, repl, cr);
11740}
11741
11742static VALUE
11743enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
11744{
11745 int encidx;
11746 VALUE buf = Qnil;
11747 const char *rep, *p, *e, *p1, *sp;
11748 long replen = -1;
11749 long slen;
11750
11751 if (rb_block_given_p()) {
11752 if (!NIL_P(repl))
11753 rb_raise(rb_eArgError, "both of block and replacement given");
11754 replen = 0;
11755 }
11756
11757 if (ENC_CODERANGE_CLEAN_P(cr))
11758 return Qnil;
11759
11760 if (!NIL_P(repl)) {
11761 repl = str_compat_and_valid(repl, enc);
11762 }
11763
11764 if (rb_enc_dummy_p(enc)) {
11765 return Qnil;
11766 }
11767 encidx = rb_enc_to_index(enc);
11768
11769#define DEFAULT_REPLACE_CHAR(str) do { \
11770 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
11771 rep = replace; replen = (int)sizeof(replace); \
11772 } while (0)
11773
11774 slen = RSTRING_LEN(str);
11775 p = RSTRING_PTR(str);
11776 e = RSTRING_END(str);
11777 p1 = p;
11778 sp = p;
11779
11780 if (rb_enc_asciicompat(enc)) {
11781 int rep7bit_p;
11782 if (!replen) {
11783 rep = NULL;
11784 rep7bit_p = FALSE;
11785 }
11786 else if (!NIL_P(repl)) {
11787 rep = RSTRING_PTR(repl);
11788 replen = RSTRING_LEN(repl);
11789 rep7bit_p = (ENC_CODERANGE(repl) == ENC_CODERANGE_7BIT);
11790 }
11791 else if (encidx == rb_utf8_encindex()) {
11792 DEFAULT_REPLACE_CHAR("\xEF\xBF\xBD");
11793 rep7bit_p = FALSE;
11794 }
11795 else {
11796 DEFAULT_REPLACE_CHAR("?");
11797 rep7bit_p = TRUE;
11798 }
11799 cr = ENC_CODERANGE_7BIT;
11800
11801 p = search_nonascii(p, e);
11802 if (!p) {
11803 p = e;
11804 }
11805 while (p < e) {
11806 int ret = rb_enc_precise_mbclen(p, e, enc);
11807 if (MBCLEN_NEEDMORE_P(ret)) {
11808 break;
11809 }
11810 else if (MBCLEN_CHARFOUND_P(ret)) {
11812 p += MBCLEN_CHARFOUND_LEN(ret);
11813 }
11814 else if (MBCLEN_INVALID_P(ret)) {
11815 /*
11816 * p1~p: valid ascii/multibyte chars
11817 * p ~e: invalid bytes + unknown bytes
11818 */
11819 long clen = rb_enc_mbmaxlen(enc);
11820 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
11821 if (p > p1) {
11822 rb_str_buf_cat(buf, p1, p - p1);
11823 }
11824
11825 if (e - p < clen) clen = e - p;
11826 if (clen <= 2) {
11827 clen = 1;
11828 }
11829 else {
11830 const char *q = p;
11831 clen--;
11832 for (; clen > 1; clen--) {
11833 ret = rb_enc_precise_mbclen(q, q + clen, enc);
11834 if (MBCLEN_NEEDMORE_P(ret)) break;
11835 if (MBCLEN_INVALID_P(ret)) continue;
11837 }
11838 }
11839 if (rep) {
11840 rb_str_buf_cat(buf, rep, replen);
11841 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
11842 }
11843 else {
11844 repl = rb_yield(rb_enc_str_new(p, clen, enc));
11845 str_mod_check(str, sp, slen);
11846 repl = str_compat_and_valid(repl, enc);
11847 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
11850 }
11851 p += clen;
11852 p1 = p;
11853 p = search_nonascii(p, e);
11854 if (!p) {
11855 p = e;
11856 break;
11857 }
11858 }
11859 else {
11861 }
11862 }
11863 if (NIL_P(buf)) {
11864 if (p == e) {
11865 ENC_CODERANGE_SET(str, cr);
11866 return Qnil;
11867 }
11868 buf = rb_str_buf_new(RSTRING_LEN(str));
11869 }
11870 if (p1 < p) {
11871 rb_str_buf_cat(buf, p1, p - p1);
11872 }
11873 if (p < e) {
11874 if (rep) {
11875 rb_str_buf_cat(buf, rep, replen);
11876 if (!rep7bit_p) cr = ENC_CODERANGE_VALID;
11877 }
11878 else {
11879 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
11880 str_mod_check(str, sp, slen);
11881 repl = str_compat_and_valid(repl, enc);
11882 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
11885 }
11886 }
11887 }
11888 else {
11889 /* ASCII incompatible */
11890 long mbminlen = rb_enc_mbminlen(enc);
11891 if (!replen) {
11892 rep = NULL;
11893 }
11894 else if (!NIL_P(repl)) {
11895 rep = RSTRING_PTR(repl);
11896 replen = RSTRING_LEN(repl);
11897 }
11898 else if (encidx == ENCINDEX_UTF_16BE) {
11899 DEFAULT_REPLACE_CHAR("\xFF\xFD");
11900 }
11901 else if (encidx == ENCINDEX_UTF_16LE) {
11902 DEFAULT_REPLACE_CHAR("\xFD\xFF");
11903 }
11904 else if (encidx == ENCINDEX_UTF_32BE) {
11905 DEFAULT_REPLACE_CHAR("\x00\x00\xFF\xFD");
11906 }
11907 else if (encidx == ENCINDEX_UTF_32LE) {
11908 DEFAULT_REPLACE_CHAR("\xFD\xFF\x00\x00");
11909 }
11910 else {
11911 DEFAULT_REPLACE_CHAR("?");
11912 }
11913
11914 while (p < e) {
11915 int ret = rb_enc_precise_mbclen(p, e, enc);
11916 if (MBCLEN_NEEDMORE_P(ret)) {
11917 break;
11918 }
11919 else if (MBCLEN_CHARFOUND_P(ret)) {
11920 p += MBCLEN_CHARFOUND_LEN(ret);
11921 }
11922 else if (MBCLEN_INVALID_P(ret)) {
11923 const char *q = p;
11924 long clen = rb_enc_mbmaxlen(enc);
11925 if (NIL_P(buf)) buf = rb_str_buf_new(RSTRING_LEN(str));
11926 if (p > p1) rb_str_buf_cat(buf, p1, p - p1);
11927
11928 if (e - p < clen) clen = e - p;
11929 if (clen <= mbminlen * 2) {
11930 clen = mbminlen;
11931 }
11932 else {
11933 clen -= mbminlen;
11934 for (; clen > mbminlen; clen-=mbminlen) {
11935 ret = rb_enc_precise_mbclen(q, q + clen, enc);
11936 if (MBCLEN_NEEDMORE_P(ret)) break;
11937 if (MBCLEN_INVALID_P(ret)) continue;
11939 }
11940 }
11941 if (rep) {
11942 rb_str_buf_cat(buf, rep, replen);
11943 }
11944 else {
11945 repl = rb_yield(rb_enc_str_new(p, clen, enc));
11946 str_mod_check(str, sp, slen);
11947 repl = str_compat_and_valid(repl, enc);
11948 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
11949 }
11950 p += clen;
11951 p1 = p;
11952 }
11953 else {
11955 }
11956 }
11957 if (NIL_P(buf)) {
11958 if (p == e) {
11960 return Qnil;
11961 }
11962 buf = rb_str_buf_new(RSTRING_LEN(str));
11963 }
11964 if (p1 < p) {
11965 rb_str_buf_cat(buf, p1, p - p1);
11966 }
11967 if (p < e) {
11968 if (rep) {
11969 rb_str_buf_cat(buf, rep, replen);
11970 }
11971 else {
11972 repl = rb_yield(rb_enc_str_new(p, e-p, enc));
11973 str_mod_check(str, sp, slen);
11974 repl = str_compat_and_valid(repl, enc);
11975 rb_str_buf_cat(buf, RSTRING_PTR(repl), RSTRING_LEN(repl));
11976 }
11977 }
11979 }
11980 ENCODING_CODERANGE_SET(buf, rb_enc_to_index(enc), cr);
11981 return buf;
11982}
11983
11984/*
11985 * call-seq:
11986 * scrub(replacement_string = default_replacement_string) -> new_string
11987 * scrub{|sequence| ... } -> new_string
11988 *
11989 * :include: doc/string/scrub.rdoc
11990 *
11991 */
11992static VALUE
11993str_scrub(int argc, VALUE *argv, VALUE str)
11994{
11995 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
11996 VALUE new = rb_str_scrub(str, repl);
11997 return NIL_P(new) ? str_duplicate(rb_cString, str): new;
11998}
11999
12000/*
12001 * call-seq:
12002 * scrub!(replacement_string = default_replacement_string) -> self
12003 * scrub!{|sequence| ... } -> self
12004 *
12005 * Like String#scrub, except that:
12006 *
12007 * - Any replacements are made in +self+.
12008 * - Returns +self+.
12009 *
12010 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12011 *
12012 */
12013static VALUE
12014str_scrub_bang(int argc, VALUE *argv, VALUE str)
12015{
12016 VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
12017 VALUE new = rb_str_scrub(str, repl);
12018 if (!NIL_P(new)) rb_str_replace(str, new);
12019 return str;
12020}
12021
12022static ID id_normalize;
12023static ID id_normalized_p;
12024static VALUE mUnicodeNormalize;
12025
12026static VALUE
12027unicode_normalize_common(int argc, VALUE *argv, VALUE str, ID id)
12028{
12029 static int UnicodeNormalizeRequired = 0;
12030 VALUE argv2[2];
12031
12032 if (!UnicodeNormalizeRequired) {
12033 rb_require("unicode_normalize/normalize.rb");
12034 UnicodeNormalizeRequired = 1;
12035 }
12036 argv2[0] = str;
12037 if (rb_check_arity(argc, 0, 1)) argv2[1] = argv[0];
12038 return rb_funcallv(mUnicodeNormalize, id, argc+1, argv2);
12039}
12040
12041/*
12042 * call-seq:
12043 * unicode_normalize(form = :nfc) -> string
12044 *
12045 * :include: doc/string/unicode_normalize.rdoc
12046 *
12047 */
12048static VALUE
12049rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
12050{
12051 return unicode_normalize_common(argc, argv, str, id_normalize);
12052}
12053
12054/*
12055 * call-seq:
12056 * unicode_normalize!(form = :nfc) -> self
12057 *
12058 * Like String#unicode_normalize, except that the normalization
12059 * is performed on +self+ (not on a copy of +self+).
12060 *
12061 * Related: see {Modifying}[rdoc-ref:String@Modifying].
12062 *
12063 */
12064static VALUE
12065rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
12066{
12067 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
12068}
12069
12070/* call-seq:
12071 * unicode_normalized?(form = :nfc) -> true or false
12072 *
12073 * Returns whether +self+ is in the given +form+ of Unicode normalization;
12074 * see String#unicode_normalize.
12075 *
12076 * The +form+ must be one of +:nfc+, +:nfd+, +:nfkc+, or +:nfkd+.
12077 *
12078 * Examples:
12079 *
12080 * "a\u0300".unicode_normalized? # => false
12081 * "a\u0300".unicode_normalized?(:nfd) # => true
12082 * "\u00E0".unicode_normalized? # => true
12083 * "\u00E0".unicode_normalized?(:nfd) # => false
12084 *
12085 *
12086 * Raises an exception if +self+ is not in a Unicode encoding:
12087 *
12088 * s = "\xE0".force_encoding(Encoding::ISO_8859_1)
12089 * s.unicode_normalized? # Raises Encoding::CompatibilityError
12090 *
12091 * Related: see {Querying}[rdoc-ref:String@Querying].
12092 */
12093static VALUE
12094rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
12095{
12096 return unicode_normalize_common(argc, argv, str, id_normalized_p);
12097}
12098
12099/**********************************************************************
12100 * Document-class: Symbol
12101 *
12102 * A +Symbol+ object represents a named identifier inside the Ruby interpreter.
12103 *
12104 * You can create a +Symbol+ object explicitly with:
12105 *
12106 * - A {symbol literal}[rdoc-ref:syntax/literals.rdoc@Symbol+Literals].
12107 *
12108 * The same +Symbol+ object will be
12109 * created for a given name or string for the duration of a program's
12110 * execution, regardless of the context or meaning of that name. Thus
12111 * if <code>Fred</code> is a constant in one context, a method in
12112 * another, and a class in a third, the +Symbol+ <code>:Fred</code>
12113 * will be the same object in all three contexts.
12114 *
12115 * module One
12116 * class Fred
12117 * end
12118 * $f1 = :Fred
12119 * end
12120 * module Two
12121 * Fred = 1
12122 * $f2 = :Fred
12123 * end
12124 * def Fred()
12125 * end
12126 * $f3 = :Fred
12127 * $f1.object_id #=> 2514190
12128 * $f2.object_id #=> 2514190
12129 * $f3.object_id #=> 2514190
12130 *
12131 * Constant, method, and variable names are returned as symbols:
12132 *
12133 * module One
12134 * Two = 2
12135 * def three; 3 end
12136 * @four = 4
12137 * @@five = 5
12138 * $six = 6
12139 * end
12140 * seven = 7
12141 *
12142 * One.constants
12143 * # => [:Two]
12144 * One.instance_methods(true)
12145 * # => [:three]
12146 * One.instance_variables
12147 * # => [:@four]
12148 * One.class_variables
12149 * # => [:@@five]
12150 * global_variables.grep(/six/)
12151 * # => [:$six]
12152 * local_variables
12153 * # => [:seven]
12154 *
12155 * A +Symbol+ object differs from a String object in that
12156 * a +Symbol+ object represents an identifier, while a String object
12157 * represents text or data.
12158 *
12159 * == What's Here
12160 *
12161 * First, what's elsewhere. Class +Symbol+:
12162 *
12163 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
12164 * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
12165 *
12166 * Here, class +Symbol+ provides methods that are useful for:
12167 *
12168 * - {Querying}[rdoc-ref:Symbol@Methods+for+Querying]
12169 * - {Comparing}[rdoc-ref:Symbol@Methods+for+Comparing]
12170 * - {Converting}[rdoc-ref:Symbol@Methods+for+Converting]
12171 *
12172 * === Methods for Querying
12173 *
12174 * - ::all_symbols: Returns an array of the symbols currently in Ruby's symbol table.
12175 * - #=~: Returns the index of the first substring in symbol that matches a
12176 * given Regexp or other object; returns +nil+ if no match is found.
12177 * - #[], #slice : Returns a substring of symbol
12178 * determined by a given index, start/length, or range, or string.
12179 * - #empty?: Returns +true+ if +self.length+ is zero; +false+ otherwise.
12180 * - #encoding: Returns the Encoding object that represents the encoding
12181 * of symbol.
12182 * - #end_with?: Returns +true+ if symbol ends with
12183 * any of the given strings.
12184 * - #match: Returns a MatchData object if symbol
12185 * matches a given Regexp; +nil+ otherwise.
12186 * - #match?: Returns +true+ if symbol
12187 * matches a given Regexp; +false+ otherwise.
12188 * - #length, #size: Returns the number of characters in symbol.
12189 * - #start_with?: Returns +true+ if symbol starts with
12190 * any of the given strings.
12191 *
12192 * === Methods for Comparing
12193 *
12194 * - #<=>: Returns -1, 0, or 1 as a given symbol is smaller than, equal to,
12195 * or larger than symbol.
12196 * - #==, #===: Returns +true+ if a given symbol has the same content and
12197 * encoding.
12198 * - #casecmp: Ignoring case, returns -1, 0, or 1 as a given
12199 * symbol is smaller than, equal to, or larger than symbol.
12200 * - #casecmp?: Returns +true+ if symbol is equal to a given symbol
12201 * after Unicode case folding; +false+ otherwise.
12202 *
12203 * === Methods for Converting
12204 *
12205 * - #capitalize: Returns symbol with the first character upcased
12206 * and all other characters downcased.
12207 * - #downcase: Returns symbol with all characters downcased.
12208 * - #inspect: Returns the string representation of +self+ as a symbol literal.
12209 * - #name: Returns the frozen string corresponding to symbol.
12210 * - #succ, #next: Returns the symbol that is the successor to symbol.
12211 * - #swapcase: Returns symbol with all upcase characters downcased
12212 * and all downcase characters upcased.
12213 * - #to_proc: Returns a Proc object which responds to the method named by symbol.
12214 * - #to_s, #id2name: Returns the string corresponding to +self+.
12215 * - #to_sym, #intern: Returns +self+.
12216 * - #upcase: Returns symbol with all characters upcased.
12217 *
12218 */
12219
12220
12221/*
12222 * call-seq:
12223 * symbol == object -> true or false
12224 *
12225 * Returns +true+ if +object+ is the same object as +self+, +false+ otherwise.
12226 */
12227
12228#define sym_equal rb_obj_equal
12229
12230static int
12231sym_printable(const char *s, const char *send, rb_encoding *enc)
12232{
12233 while (s < send) {
12234 int n;
12235 int c = rb_enc_precise_mbclen(s, send, enc);
12236
12237 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
12238 n = MBCLEN_CHARFOUND_LEN(c);
12239 c = rb_enc_mbc_to_codepoint(s, send, enc);
12240 if (!rb_enc_isprint(c, enc)) return FALSE;
12241 s += n;
12242 }
12243 return TRUE;
12244}
12245
12246int
12247rb_str_symname_p(VALUE sym)
12248{
12249 rb_encoding *enc;
12250 const char *ptr;
12251 long len;
12252 rb_encoding *resenc = rb_default_internal_encoding();
12253
12254 if (resenc == NULL) resenc = rb_default_external_encoding();
12255 enc = STR_ENC_GET(sym);
12256 ptr = RSTRING_PTR(sym);
12257 len = RSTRING_LEN(sym);
12258 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) || len != (long)strlen(ptr) ||
12259 !rb_enc_symname2_p(ptr, len, enc) || !sym_printable(ptr, ptr + len, enc)) {
12260 return FALSE;
12261 }
12262 return TRUE;
12263}
12264
12265VALUE
12266rb_str_quote_unprintable(VALUE str)
12267{
12268 rb_encoding *enc;
12269 const char *ptr;
12270 long len;
12271 rb_encoding *resenc;
12272
12273 Check_Type(str, T_STRING);
12274 resenc = rb_default_internal_encoding();
12275 if (resenc == NULL) resenc = rb_default_external_encoding();
12276 enc = STR_ENC_GET(str);
12277 ptr = RSTRING_PTR(str);
12278 len = RSTRING_LEN(str);
12279 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
12280 !sym_printable(ptr, ptr + len, enc)) {
12281 return rb_str_escape(str);
12282 }
12283 return str;
12284}
12285
12286VALUE
12287rb_id_quote_unprintable(ID id)
12288{
12289 VALUE str = rb_id2str(id);
12290 if (!rb_str_symname_p(str)) {
12291 return rb_str_escape(str);
12292 }
12293 return str;
12294}
12295
12296/*
12297 * call-seq:
12298 * inspect -> string
12299 *
12300 * Returns a string representation of +self+ (including the leading colon):
12301 *
12302 * :foo.inspect # => ":foo"
12303 *
12304 * Related: Symbol#to_s, Symbol#name.
12305 *
12306 */
12307
12308static VALUE
12309sym_inspect(VALUE sym)
12310{
12311 VALUE str = rb_sym2str(sym);
12312 const char *ptr;
12313 long len;
12314 char *dest;
12315
12316 if (!rb_str_symname_p(str)) {
12317 str = rb_str_inspect(str);
12318 len = RSTRING_LEN(str);
12319 rb_str_resize(str, len + 1);
12320 dest = RSTRING_PTR(str);
12321 memmove(dest + 1, dest, len);
12322 }
12323 else {
12324 rb_encoding *enc = STR_ENC_GET(str);
12325 VALUE orig_str = str;
12326
12327 len = RSTRING_LEN(orig_str);
12328 str = rb_enc_str_new(0, len + 1, enc);
12329
12330 // Get data pointer after allocation
12331 ptr = RSTRING_PTR(orig_str);
12332 dest = RSTRING_PTR(str);
12333 memcpy(dest + 1, ptr, len);
12334
12335 RB_GC_GUARD(orig_str);
12336 }
12337 dest[0] = ':';
12338
12340
12341 return str;
12342}
12343
12344VALUE
12346{
12347 VALUE str = str_new_shared(rb_cString, rb_sym2str(sym));
12348 FL_SET_RAW(str, STR_CHILLED_SYMBOL_TO_S);
12349 return str;
12350}
12351
12352VALUE
12353rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc)
12354{
12355 VALUE obj;
12356
12357 if (argc < 1) {
12358 rb_raise(rb_eArgError, "no receiver given");
12359 }
12360 obj = argv[0];
12361 return rb_funcall_with_block_kw(obj, mid, argc - 1, argv + 1, passed_proc, kw_splat);
12362}
12363
12364/*
12365 * call-seq:
12366 * succ
12367 *
12368 * Equivalent to <tt>self.to_s.succ.to_sym</tt>:
12369 *
12370 * :foo.succ # => :fop
12371 *
12372 * Related: String#succ.
12373 */
12374
12375static VALUE
12376sym_succ(VALUE sym)
12377{
12378 return rb_str_intern(rb_str_succ(rb_sym2str(sym)));
12379}
12380
12381/*
12382 * call-seq:
12383 * self <=> other -> -1, 0, 1, or nil
12384 *
12385 * Compares +self+ and +other+, using String#<=>.
12386 *
12387 * Returns:
12388 *
12389 * - <tt>self.to_s <=> other.to_s</tt>, if +other+ is a symbol.
12390 * - +nil+, otherwise.
12391 *
12392 * Examples:
12393 *
12394 * :bar <=> :foo # => -1
12395 * :foo <=> :foo # => 0
12396 * :foo <=> :bar # => 1
12397 * :foo <=> 'bar' # => nil
12398 *
12399 * \Class \Symbol includes module Comparable,
12400 * each of whose methods uses Symbol#<=> for comparison.
12401 *
12402 * Related: String#<=>.
12403 */
12404
12405static VALUE
12406sym_cmp(VALUE sym, VALUE other)
12407{
12408 if (!SYMBOL_P(other)) {
12409 return Qnil;
12410 }
12411 return rb_str_cmp_m(rb_sym2str(sym), rb_sym2str(other));
12412}
12413
12414/*
12415 * call-seq:
12416 * casecmp(object) -> -1, 0, 1, or nil
12417 *
12418 * :include: doc/symbol/casecmp.rdoc
12419 *
12420 */
12421
12422static VALUE
12423sym_casecmp(VALUE sym, VALUE other)
12424{
12425 if (!SYMBOL_P(other)) {
12426 return Qnil;
12427 }
12428 return str_casecmp(rb_sym2str(sym), rb_sym2str(other));
12429}
12430
12431/*
12432 * call-seq:
12433 * casecmp?(object) -> true, false, or nil
12434 *
12435 * :include: doc/symbol/casecmp_p.rdoc
12436 *
12437 */
12438
12439static VALUE
12440sym_casecmp_p(VALUE sym, VALUE other)
12441{
12442 if (!SYMBOL_P(other)) {
12443 return Qnil;
12444 }
12445 return str_casecmp_p(rb_sym2str(sym), rb_sym2str(other));
12446}
12447
12448/*
12449 * call-seq:
12450 * symbol =~ object -> integer or nil
12451 *
12452 * Equivalent to <tt>symbol.to_s =~ object</tt>,
12453 * including possible updates to global variables;
12454 * see String#=~.
12455 *
12456 */
12457
12458static VALUE
12459sym_match(VALUE sym, VALUE other)
12460{
12461 return rb_str_match(rb_sym2str(sym), other);
12462}
12463
12464/*
12465 * call-seq:
12466 * match(pattern, offset = 0) -> matchdata or nil
12467 * match(pattern, offset = 0) {|matchdata| } -> object
12468 *
12469 * Equivalent to <tt>self.to_s.match</tt>,
12470 * including possible updates to global variables;
12471 * see String#match.
12472 *
12473 */
12474
12475static VALUE
12476sym_match_m(int argc, VALUE *argv, VALUE sym)
12477{
12478 return rb_str_match_m(argc, argv, rb_sym2str(sym));
12479}
12480
12481/*
12482 * call-seq:
12483 * match?(pattern, offset) -> true or false
12484 *
12485 * Equivalent to <tt>sym.to_s.match?</tt>;
12486 * see String#match.
12487 *
12488 */
12489
12490static VALUE
12491sym_match_m_p(int argc, VALUE *argv, VALUE sym)
12492{
12493 return rb_str_match_m_p(argc, argv, sym);
12494}
12495
12496/*
12497 * call-seq:
12498 * symbol[index] -> string or nil
12499 * symbol[start, length] -> string or nil
12500 * symbol[range] -> string or nil
12501 * symbol[regexp, capture = 0] -> string or nil
12502 * symbol[substring] -> string or nil
12503 *
12504 * Equivalent to <tt>symbol.to_s[]</tt>; see String#[].
12505 *
12506 */
12507
12508static VALUE
12509sym_aref(int argc, VALUE *argv, VALUE sym)
12510{
12511 return rb_str_aref_m(argc, argv, rb_sym2str(sym));
12512}
12513
12514/*
12515 * call-seq:
12516 * length -> integer
12517 *
12518 * Equivalent to <tt>self.to_s.length</tt>; see String#length.
12519 */
12520
12521static VALUE
12522sym_length(VALUE sym)
12523{
12524 return rb_str_length(rb_sym2str(sym));
12525}
12526
12527/*
12528 * call-seq:
12529 * empty? -> true or false
12530 *
12531 * Returns +true+ if +self+ is <tt>:''</tt>, +false+ otherwise.
12532 *
12533 */
12534
12535static VALUE
12536sym_empty(VALUE sym)
12537{
12538 return rb_str_empty(rb_sym2str(sym));
12539}
12540
12541/*
12542 * call-seq:
12543 * upcase(mapping) -> symbol
12544 *
12545 * Equivalent to <tt>sym.to_s.upcase.to_sym</tt>.
12546 *
12547 * See String#upcase.
12548 *
12549 */
12550
12551static VALUE
12552sym_upcase(int argc, VALUE *argv, VALUE sym)
12553{
12554 return rb_str_intern(rb_str_upcase(argc, argv, rb_sym2str(sym)));
12555}
12556
12557/*
12558 * call-seq:
12559 * downcase(mapping) -> symbol
12560 *
12561 * Equivalent to <tt>sym.to_s.downcase.to_sym</tt>.
12562 *
12563 * See String#downcase.
12564 *
12565 * Related: Symbol#upcase.
12566 *
12567 */
12568
12569static VALUE
12570sym_downcase(int argc, VALUE *argv, VALUE sym)
12571{
12572 return rb_str_intern(rb_str_downcase(argc, argv, rb_sym2str(sym)));
12573}
12574
12575/*
12576 * call-seq:
12577 * capitalize(mapping) -> symbol
12578 *
12579 * Equivalent to <tt>sym.to_s.capitalize.to_sym</tt>.
12580 *
12581 * See String#capitalize.
12582 *
12583 */
12584
12585static VALUE
12586sym_capitalize(int argc, VALUE *argv, VALUE sym)
12587{
12588 return rb_str_intern(rb_str_capitalize(argc, argv, rb_sym2str(sym)));
12589}
12590
12591/*
12592 * call-seq:
12593 * swapcase(mapping) -> symbol
12594 *
12595 * Equivalent to <tt>sym.to_s.swapcase.to_sym</tt>.
12596 *
12597 * See String#swapcase.
12598 *
12599 */
12600
12601static VALUE
12602sym_swapcase(int argc, VALUE *argv, VALUE sym)
12603{
12604 return rb_str_intern(rb_str_swapcase(argc, argv, rb_sym2str(sym)));
12605}
12606
12607/*
12608 * call-seq:
12609 * start_with?(*string_or_regexp) -> true or false
12610 *
12611 * Equivalent to <tt>self.to_s.start_with?</tt>; see String#start_with?.
12612 *
12613 */
12614
12615static VALUE
12616sym_start_with(int argc, VALUE *argv, VALUE sym)
12617{
12618 return rb_str_start_with(argc, argv, rb_sym2str(sym));
12619}
12620
12621/*
12622 * call-seq:
12623 * end_with?(*strings) -> true or false
12624 *
12625 *
12626 * Equivalent to <tt>self.to_s.end_with?</tt>; see String#end_with?.
12627 *
12628 */
12629
12630static VALUE
12631sym_end_with(int argc, VALUE *argv, VALUE sym)
12632{
12633 return rb_str_end_with(argc, argv, rb_sym2str(sym));
12634}
12635
12636/*
12637 * call-seq:
12638 * encoding -> encoding
12639 *
12640 * Equivalent to <tt>self.to_s.encoding</tt>; see String#encoding.
12641 *
12642 */
12643
12644static VALUE
12645sym_encoding(VALUE sym)
12646{
12647 return rb_obj_encoding(rb_sym2str(sym));
12648}
12649
12650static VALUE
12651string_for_symbol(VALUE name)
12652{
12653 if (!RB_TYPE_P(name, T_STRING)) {
12654 VALUE tmp = rb_check_string_type(name);
12655 if (NIL_P(tmp)) {
12656 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
12657 name);
12658 }
12659 name = tmp;
12660 }
12661 return name;
12662}
12663
12664ID
12666{
12667 if (SYMBOL_P(name)) {
12668 return SYM2ID(name);
12669 }
12670 name = string_for_symbol(name);
12671 return rb_intern_str(name);
12672}
12673
12674VALUE
12676{
12677 if (SYMBOL_P(name)) {
12678 return name;
12679 }
12680 name = string_for_symbol(name);
12681 return rb_str_intern(name);
12682}
12683
12684/*
12685 * call-seq:
12686 * Symbol.all_symbols -> array_of_symbols
12687 *
12688 * Returns an array of all symbols currently in Ruby's symbol table:
12689 *
12690 * Symbol.all_symbols.size # => 9334
12691 * Symbol.all_symbols.take(3) # => [:!, :"\"", :"#"]
12692 *
12693 */
12694
12695static VALUE
12696sym_all_symbols(VALUE _)
12697{
12698 return rb_sym_all_symbols();
12699}
12700
12701VALUE
12702rb_str_to_interned_str(VALUE str)
12703{
12704 return rb_fstring(str);
12705}
12706
12707VALUE
12708rb_interned_str(const char *ptr, long len)
12709{
12710 struct RString fake_str = {RBASIC_INIT};
12711 int encidx = ENCINDEX_US_ASCII;
12712 int coderange = ENC_CODERANGE_7BIT;
12713 if (len > 0 && search_nonascii(ptr, ptr + len)) {
12714 encidx = ENCINDEX_ASCII_8BIT;
12715 coderange = ENC_CODERANGE_VALID;
12716 }
12717 VALUE str = setup_fake_str(&fake_str, ptr, len, encidx);
12718 ENC_CODERANGE_SET(str, coderange);
12719 return register_fstring(str, true, false);
12720}
12721
12722VALUE
12724{
12725 return rb_interned_str(ptr, strlen(ptr));
12726}
12727
12728VALUE
12729rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
12730{
12731 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
12732 rb_enc_autoload(enc);
12733 }
12734
12735 struct RString fake_str = {RBASIC_INIT};
12736 return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, false);
12737}
12738
12739VALUE
12740rb_enc_literal_str(const char *ptr, long len, rb_encoding *enc)
12741{
12742 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
12743 rb_enc_autoload(enc);
12744 }
12745
12746 struct RString fake_str = {RBASIC_INIT};
12747 VALUE str = register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true);
12748 RUBY_ASSERT(RB_OBJ_SHAREABLE_P(str) && (rb_gc_verify_shareable(str), 1));
12749 return str;
12750}
12751
12752VALUE
12753rb_enc_interned_str_cstr(const char *ptr, rb_encoding *enc)
12754{
12755 return rb_enc_interned_str(ptr, strlen(ptr), enc);
12756}
12757
12758#if USE_YJIT || USE_ZJIT
12759void
12760rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint)
12761{
12762 if (RB_LIKELY(ENCODING_GET_INLINED(str) == rb_ascii8bit_encindex())) {
12763 ssize_t code = RB_NUM2SSIZE(codepoint);
12764
12765 if (RB_LIKELY(code >= 0 && code < 0xff)) {
12766 rb_str_buf_cat_byte(str, (char) code);
12767 return;
12768 }
12769 }
12770
12771 rb_str_concat(str, codepoint);
12772}
12773#endif
12774
12775static int
12776fstring_set_class_i(VALUE *str, void *data)
12777{
12778 RBASIC_SET_CLASS(*str, rb_cString);
12779
12780 return ST_CONTINUE;
12781}
12782
12783void
12784Init_String(void)
12785{
12786 rb_cString = rb_define_class("String", rb_cObject);
12787
12788 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
12789
12791 rb_define_alloc_func(rb_cString, empty_str_alloc);
12792 rb_define_singleton_method(rb_cString, "new", rb_str_s_new, -1);
12793 rb_define_singleton_method(rb_cString, "try_convert", rb_str_s_try_convert, 1);
12794 rb_define_method(rb_cString, "initialize", rb_str_init, -1);
12796 rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1);
12797 rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
12800 rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
12801 rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
12802 rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
12803 rb_define_method(rb_cString, "casecmp?", rb_str_casecmp_p, 1);
12806 rb_define_method(rb_cString, "%", rb_str_format_m, 1);
12807 rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
12808 rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
12809 rb_define_method(rb_cString, "insert", rb_str_insert, 2);
12812 rb_define_method(rb_cString, "bytesize", rb_str_bytesize, 0);
12813 rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
12814 rb_define_method(rb_cString, "=~", rb_str_match, 1);
12815 rb_define_method(rb_cString, "match", rb_str_match_m, -1);
12816 rb_define_method(rb_cString, "match?", rb_str_match_m_p, -1);
12818 rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0);
12820 rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0);
12821 rb_define_method(rb_cString, "upto", rb_str_upto, -1);
12822 rb_define_method(rb_cString, "index", rb_str_index_m, -1);
12823 rb_define_method(rb_cString, "byteindex", rb_str_byteindex_m, -1);
12824 rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1);
12825 rb_define_method(rb_cString, "byterindex", rb_str_byterindex_m, -1);
12826 rb_define_method(rb_cString, "clear", rb_str_clear, 0);
12827 rb_define_method(rb_cString, "chr", rb_str_chr, 0);
12828 rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
12829 rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);
12830 rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);
12831 rb_define_method(rb_cString, "bytesplice", rb_str_bytesplice, -1);
12832 rb_define_method(rb_cString, "scrub", str_scrub, -1);
12833 rb_define_method(rb_cString, "scrub!", str_scrub_bang, -1);
12835 rb_define_method(rb_cString, "+@", str_uplus, 0);
12836 rb_define_method(rb_cString, "-@", str_uminus, 0);
12837 rb_define_method(rb_cString, "dup", rb_str_dup_m, 0);
12838 rb_define_alias(rb_cString, "dedup", "-@");
12839
12840 rb_define_method(rb_cString, "to_i", rb_str_to_i, -1);
12841 rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);
12842 rb_define_method(rb_cString, "to_s", rb_str_to_s, 0);
12843 rb_define_method(rb_cString, "to_str", rb_str_to_s, 0);
12846 rb_define_method(rb_cString, "undump", str_undump, 0);
12847
12848 sym_ascii = ID2SYM(rb_intern_const("ascii"));
12849 sym_turkic = ID2SYM(rb_intern_const("turkic"));
12850 sym_lithuanian = ID2SYM(rb_intern_const("lithuanian"));
12851 sym_fold = ID2SYM(rb_intern_const("fold"));
12852
12853 rb_define_method(rb_cString, "upcase", rb_str_upcase, -1);
12854 rb_define_method(rb_cString, "downcase", rb_str_downcase, -1);
12855 rb_define_method(rb_cString, "capitalize", rb_str_capitalize, -1);
12856 rb_define_method(rb_cString, "swapcase", rb_str_swapcase, -1);
12857
12858 rb_define_method(rb_cString, "upcase!", rb_str_upcase_bang, -1);
12859 rb_define_method(rb_cString, "downcase!", rb_str_downcase_bang, -1);
12860 rb_define_method(rb_cString, "capitalize!", rb_str_capitalize_bang, -1);
12861 rb_define_method(rb_cString, "swapcase!", rb_str_swapcase_bang, -1);
12862
12863 rb_define_method(rb_cString, "hex", rb_str_hex, 0);
12864 rb_define_method(rb_cString, "oct", rb_str_oct, 0);
12865 rb_define_method(rb_cString, "split", rb_str_split_m, -1);
12866 rb_define_method(rb_cString, "lines", rb_str_lines, -1);
12867 rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
12868 rb_define_method(rb_cString, "chars", rb_str_chars, 0);
12869 rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
12870 rb_define_method(rb_cString, "grapheme_clusters", rb_str_grapheme_clusters, 0);
12871 rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
12872 rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
12873 rb_define_method(rb_cString, "concat", rb_str_concat_multi, -1);
12874 rb_define_method(rb_cString, "append_as_bytes", rb_str_append_as_bytes, -1);
12876 rb_define_method(rb_cString, "prepend", rb_str_prepend_multi, -1);
12877 rb_define_method(rb_cString, "crypt", rb_str_crypt, 1);
12878 rb_define_method(rb_cString, "intern", rb_str_intern, 0); /* in symbol.c */
12879 rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); /* in symbol.c */
12880 rb_define_method(rb_cString, "ord", rb_str_ord, 0);
12881
12882 rb_define_method(rb_cString, "include?", rb_str_include, 1);
12883 rb_define_method(rb_cString, "start_with?", rb_str_start_with, -1);
12884 rb_define_method(rb_cString, "end_with?", rb_str_end_with, -1);
12885
12886 rb_define_method(rb_cString, "scan", rb_str_scan, 1);
12887
12888 rb_define_method(rb_cString, "ljust", rb_str_ljust, -1);
12889 rb_define_method(rb_cString, "rjust", rb_str_rjust, -1);
12890 rb_define_method(rb_cString, "center", rb_str_center, -1);
12891
12892 rb_define_method(rb_cString, "sub", rb_str_sub, -1);
12893 rb_define_method(rb_cString, "gsub", rb_str_gsub, -1);
12894 rb_define_method(rb_cString, "chop", rb_str_chop, 0);
12895 rb_define_method(rb_cString, "chomp", rb_str_chomp, -1);
12896 rb_define_method(rb_cString, "strip", rb_str_strip, -1);
12897 rb_define_method(rb_cString, "lstrip", rb_str_lstrip, -1);
12898 rb_define_method(rb_cString, "rstrip", rb_str_rstrip, -1);
12899 rb_define_method(rb_cString, "delete_prefix", rb_str_delete_prefix, 1);
12900 rb_define_method(rb_cString, "delete_suffix", rb_str_delete_suffix, 1);
12901
12902 rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1);
12903 rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1);
12904 rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0);
12905 rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1);
12906 rb_define_method(rb_cString, "strip!", rb_str_strip_bang, -1);
12907 rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, -1);
12908 rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, -1);
12909 rb_define_method(rb_cString, "delete_prefix!", rb_str_delete_prefix_bang, 1);
12910 rb_define_method(rb_cString, "delete_suffix!", rb_str_delete_suffix_bang, 1);
12911
12912 rb_define_method(rb_cString, "tr", rb_str_tr, 2);
12913 rb_define_method(rb_cString, "tr_s", rb_str_tr_s, 2);
12914 rb_define_method(rb_cString, "delete", rb_str_delete, -1);
12915 rb_define_method(rb_cString, "squeeze", rb_str_squeeze, -1);
12916 rb_define_method(rb_cString, "count", rb_str_count, -1);
12917
12918 rb_define_method(rb_cString, "tr!", rb_str_tr_bang, 2);
12919 rb_define_method(rb_cString, "tr_s!", rb_str_tr_s_bang, 2);
12920 rb_define_method(rb_cString, "delete!", rb_str_delete_bang, -1);
12921 rb_define_method(rb_cString, "squeeze!", rb_str_squeeze_bang, -1);
12922
12923 rb_define_method(rb_cString, "each_line", rb_str_each_line, -1);
12924 rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0);
12925 rb_define_method(rb_cString, "each_char", rb_str_each_char, 0);
12926 rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0);
12927 rb_define_method(rb_cString, "each_grapheme_cluster", rb_str_each_grapheme_cluster, 0);
12928
12929 rb_define_method(rb_cString, "sum", rb_str_sum, -1);
12930
12931 rb_define_method(rb_cString, "slice", rb_str_aref_m, -1);
12932 rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1);
12933
12934 rb_define_method(rb_cString, "partition", rb_str_partition, 1);
12935 rb_define_method(rb_cString, "rpartition", rb_str_rpartition, 1);
12936
12937 rb_define_method(rb_cString, "encoding", rb_obj_encoding, 0); /* in encoding.c */
12938 rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1);
12939 rb_define_method(rb_cString, "b", rb_str_b, 0);
12940 rb_define_method(rb_cString, "valid_encoding?", rb_str_valid_encoding_p, 0);
12941 rb_define_method(rb_cString, "ascii_only?", rb_str_is_ascii_only_p, 0);
12942
12943 /* define UnicodeNormalize module here so that we don't have to look it up */
12944 mUnicodeNormalize = rb_define_module("UnicodeNormalize");
12945 id_normalize = rb_intern_const("normalize");
12946 id_normalized_p = rb_intern_const("normalized?");
12947
12948 rb_define_method(rb_cString, "unicode_normalize", rb_str_unicode_normalize, -1);
12949 rb_define_method(rb_cString, "unicode_normalize!", rb_str_unicode_normalize_bang, -1);
12950 rb_define_method(rb_cString, "unicode_normalized?", rb_str_unicode_normalized_p, -1);
12951
12952 rb_fs = Qnil;
12953 rb_define_hooked_variable("$;", &rb_fs, 0, rb_fs_setter);
12954 rb_define_hooked_variable("$-F", &rb_fs, 0, rb_fs_setter);
12955 rb_gc_register_address(&rb_fs);
12956
12957 rb_cSymbol = rb_define_class("Symbol", rb_cObject);
12961 rb_define_singleton_method(rb_cSymbol, "all_symbols", sym_all_symbols, 0);
12962
12963 rb_define_method(rb_cSymbol, "==", sym_equal, 1);
12964 rb_define_method(rb_cSymbol, "===", sym_equal, 1);
12965 rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
12966 rb_define_method(rb_cSymbol, "to_proc", rb_sym_to_proc, 0); /* in proc.c */
12967 rb_define_method(rb_cSymbol, "succ", sym_succ, 0);
12968 rb_define_method(rb_cSymbol, "next", sym_succ, 0);
12969
12970 rb_define_method(rb_cSymbol, "<=>", sym_cmp, 1);
12971 rb_define_method(rb_cSymbol, "casecmp", sym_casecmp, 1);
12972 rb_define_method(rb_cSymbol, "casecmp?", sym_casecmp_p, 1);
12973 rb_define_method(rb_cSymbol, "=~", sym_match, 1);
12974
12975 rb_define_method(rb_cSymbol, "[]", sym_aref, -1);
12976 rb_define_method(rb_cSymbol, "slice", sym_aref, -1);
12977 rb_define_method(rb_cSymbol, "length", sym_length, 0);
12978 rb_define_method(rb_cSymbol, "size", sym_length, 0);
12979 rb_define_method(rb_cSymbol, "empty?", sym_empty, 0);
12980 rb_define_method(rb_cSymbol, "match", sym_match_m, -1);
12981 rb_define_method(rb_cSymbol, "match?", sym_match_m_p, -1);
12982
12983 rb_define_method(rb_cSymbol, "upcase", sym_upcase, -1);
12984 rb_define_method(rb_cSymbol, "downcase", sym_downcase, -1);
12985 rb_define_method(rb_cSymbol, "capitalize", sym_capitalize, -1);
12986 rb_define_method(rb_cSymbol, "swapcase", sym_swapcase, -1);
12987
12988 rb_define_method(rb_cSymbol, "start_with?", sym_start_with, -1);
12989 rb_define_method(rb_cSymbol, "end_with?", sym_end_with, -1);
12990
12991 rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0);
12992}
12993
#define RUBY_ASSERT_ALWAYS(expr,...)
A variant of RUBY_ASSERT that does not interface with RUBY_DEBUG.
Definition assert.h:199
#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
#define ISSPACE
@old{rb_isspace}
Definition ctype.h:88
#define ISDIGIT
@old{rb_isdigit}
Definition ctype.h:93
#define ISALPHA
@old{rb_isalpha}
Definition ctype.h:92
#define TOLOWER
@old{rb_tolower}
Definition ctype.h:101
#define ISPRINT
@old{rb_isprint}
Definition ctype.h:86
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
Definition sprintf.c:1198
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1695
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1488
VALUE rb_define_module(const char *name)
Defines a top-level module.
Definition class.c:1601
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2868
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2680
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:3158
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1021
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2947
#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:133
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1683
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define 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 xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#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:136
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#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 ENC_CODERANGE_MASK
Old name of RUBY_ENC_CODERANGE_MASK.
Definition coderange.h:178
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:131
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#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:125
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define Qtrue
Old name of RUBY_Qtrue.
#define ST2FIX
Old name of RB_ST2FIX.
Definition st_data_t.h:33
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define FIXNUM_MAX
Old name of RUBY_FIXNUM_MAX.
Definition fixnum.h:26
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define scan_hex(s, l, e)
Old name of ruby_scan_hex.
Definition util.h:108
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define FL_WB_PROTECTED
Old name of RUBY_FL_WB_PROTECTED.
Definition fl_type.h:59
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#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:130
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:66
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define ENCODING_GET_INLINED(obj)
Old name of RB_ENCODING_GET_INLINED.
Definition encoding.h:108
#define ENC_CODERANGE_CLEAR(obj)
Old name of RB_ENC_CODERANGE_CLEAR.
Definition coderange.h:187
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define ENCODING_IS_ASCII8BIT(obj)
Old name of RB_ENCODING_IS_ASCII8BIT.
Definition encoding.h:110
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define ENCODING_CODERANGE_SET(obj, encindex, cr)
Old name of RB_ENCODING_CODERANGE_SET.
Definition coderange.h:189
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
Definition fl_type.h:129
#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:137
#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:476
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:664
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3909
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1435
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
Definition error.c:1438
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition eval.c:1172
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:675
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2208
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:2226
VALUE rb_obj_frozen_p(VALUE obj)
Just calls RB_OBJ_FROZEN() inside.
Definition object.c:1354
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:3622
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:264
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:582
VALUE rb_cSymbol
Symbol class.
Definition string.c:85
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:176
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
VALUE rb_mComparable
Comparable module.
Definition compar.c:19
VALUE rb_cString
String class.
Definition string.c:84
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3306
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
Encoding relates APIs.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1342
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:947
VALUE rb_enc_str_new_static(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it takes a C string literal.
Definition string.c:1207
char * rb_enc_nth(const char *head, const char *tail, long nth, rb_encoding *enc)
Queries the n-th character.
Definition string.c:3031
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:1226
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
Definition string.c:12729
long rb_memsearch(const void *x, long m, const void *y, long n, rb_encoding *enc)
Looks for the passed string in the passed buffer.
Definition re.c:253
long rb_enc_strlen(const char *head, const char *tail, rb_encoding *enc)
Counts the number of characters of the passed string, according to the passed encoding.
Definition string.c:2335
VALUE rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *enc)
Identical to rb_str_cat(), except it additionally takes an encoding.
Definition string.c:3735
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:1155
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:1447
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *enc)
Identical to rb_external_str_new(), except it additionally takes an encoding.
Definition string.c:1348
int rb_enc_str_asciionly_p(VALUE str)
Queries if the passed string is "ASCII only".
Definition string.c:966
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:12753
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:831
int rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
Identical to rb_enc_symname_p(), except it additionally takes the passed string's length.
Definition symbol.c:703
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:2726
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:2989
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1743
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
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:1204
#define RGENGC_WB_PROTECTED_STRING
This is a compile-time flag to enable/disable write barrier for struct RString.
Definition gc.h:479
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
This roughly resembles return enum_for(__callee__) unless block_given?.
Definition enumerator.h:208
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Definition error.h:35
VALUE rb_fs
The field separator character for inputs, or the $;.
Definition string.c:714
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:211
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
Definition vm.c:2033
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:1060
void rb_backref_set(VALUE md)
Updates $~.
Definition vm.c:2039
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
Definition range.c:1950
int rb_reg_backref_number(VALUE match, VALUE backref)
Queries the index of the given named capture.
Definition re.c:1231
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4223
VALUE rb_reg_match(VALUE re, VALUE str)
This is the match operator.
Definition re.c:3720
void rb_match_busy(VALUE md)
Asserts that the given MatchData is "occupied".
Definition re.c:1485
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
Definition re.c:1922
void rb_str_free(VALUE str)
Destroys the given string for no reason.
Definition string.c:1752
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:1512
VALUE rb_str_plus(VALUE lhs, VALUE rhs)
Generates a new string, concatenating the former to the latter.
Definition string.c:2488
#define rb_utf8_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "UTF-8" encoding.
Definition string.h:1584
#define rb_hash_end(h)
Just another name of st_hash_end.
Definition string.h:946
#define rb_hash_uint32(h, i)
Just another name of st_hash_uint32.
Definition string.h:940
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3800
VALUE rb_filesystem_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "filesystem" encoding.
Definition string.c:1423
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
Definition string.c:12345
VALUE rb_str_times(VALUE str, VALUE num)
Repetition of a string.
Definition string.c:2561
VALUE rb_external_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "defaultexternal" encoding.
Definition string.c:1399
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1746
long rb_str_offset(VALUE str, long pos)
"Inverse" of rb_str_sublen().
Definition string.c:3059
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
Definition string.c:5342
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4163
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
Definition string.c:3156
VALUE rb_str_ellipsize(VALUE str, long len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
Definition string.c:11666
st_index_t rb_memhash(const void *ptr, long len)
This is a universal hash function.
Definition random.c:1782
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
void rb_str_shared_replace(VALUE dst, VALUE src)
Replaces the contents of the former with the latter.
Definition string.c:1788
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
VALUE rb_str_new_static(const char *ptr, long len)
Identical to rb_str_new(), except it takes a C string literal.
Definition string.c:1189
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1001
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1518
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1997
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4149
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3568
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
long rb_str_strlen(VALUE str)
Counts the number of characters (not bytes) that are stored inside of the given string.
Definition string.c:2424
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:2015
#define rb_str_buf_new_cstr(str)
Identical to rb_str_new_cstr, except done differently.
Definition string.h:1640
#define rb_usascii_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "US ASCII" encoding.
Definition string.h:1568
VALUE rb_str_replace(VALUE dst, VALUE src)
Replaces the contents of the former object with the stringised contents of the latter.
Definition string.c:6549
char * rb_str_subpos(VALUE str, long beg, long *len)
Identical to rb_str_substr(), except it returns a C's string instead of Ruby's.
Definition string.c:3164
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1147
VALUE rb_interned_str_cstr(const char *ptr)
Identical to rb_interned_str(), except it assumes the passed pointer is a pointer to a C's string.
Definition string.c:12723
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:1429
#define rb_external_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "defaultexternal" encoding.
Definition string.h:1605
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3766
long rb_str_sublen(VALUE str, long pos)
Byte offset to character offset conversion.
Definition string.c:3106
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4270
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3390
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:7228
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2793
VALUE rb_interned_str(const char *ptr, long len)
Identical to rb_str_new(), except it returns an infamous "f"string.
Definition string.c:12708
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4217
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:4037
int rb_str_comparable(VALUE str1, VALUE str2)
Checks if two strings are comparable each other or not.
Definition string.c:4192
#define rb_strlen_lit(str)
Length of a string literal.
Definition string.h:1693
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3742
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3281
void rb_str_update(VALUE dst, long beg, long len, VALUE src)
Replaces some (or all) of the contents of the given string.
Definition string.c:5826
VALUE rb_str_scrub(VALUE str, VALUE repl)
"Cleanses" the string.
Definition string.c:11724
#define rb_locale_str_new_cstr(str)
Identical to rb_external_str_new_cstr, except it generates a string of "locale" encoding instead of "...
Definition string.h:1626
VALUE rb_str_new_with_class(VALUE obj, const char *ptr, long len)
Identical to rb_str_new(), except it takes the class of the allocating object.
Definition string.c:1702
#define rb_str_dup_frozen
Just another name of rb_str_new_frozen.
Definition string.h:632
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2953
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3253
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1657
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3372
VALUE rb_utf8_str_new_static(const char *ptr, long len)
Identical to rb_str_new_static(), except it generates a string of "UTF-8" encoding instead of "binary...
Definition string.c:1201
#define rb_utf8_str_new(str, len)
Identical to rb_str_new, except it generates a string of "UTF-8" encoding.
Definition string.h:1550
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2747
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
Definition string.c:7335
VALUE rb_locale_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "locale" encoding.
Definition string.c:1411
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1718
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
Definition string.c:2438
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_str_drop_bytes(VALUE str, long len)
Shrinks the given string for the given number of bytes.
Definition string.c:5744
VALUE rb_str_split(VALUE str, const char *delim)
Divides the given string based on the given delimiter.
Definition string.c:9342
VALUE rb_usascii_str_new_static(const char *ptr, long len)
Identical to rb_str_new_static(), except it generates a string of "US ASCII" encoding instead of "bin...
Definition string.c:1195
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:937
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:1851
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:2030
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
Definition variable.c:2109
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3471
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1719
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:993
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
Definition string.c:12675
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:12665
int capa
Designed capacity of the buffer.
Definition io.h:11
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
int off
Offset inside of ptr.
Definition io.h:5
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
long rb_reg_search(VALUE re, VALUE str, long pos, int dir)
Runs the passed regular expression over the passed string.
Definition re.c:1861
VALUE rb_reg_regcomp(VALUE str)
Creates a new instance of rb_cRegexp.
Definition re.c:3499
VALUE rb_reg_regsub(VALUE repl, VALUE src, struct re_registers *regs, VALUE rexp)
Substitution.
Definition re.c:4467
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt)
Formats a string.
Definition sprintf.c:215
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
VALUE type(ANYARGS)
ANYARGS-ed function type.
Defines RBIMPL_ATTR_NONSTRING.
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define DATA_PTR(obj)
Convenient getter macro.
Definition rdata.h:67
#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:1441
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:2930
#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:2812
#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:1435
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:2825
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:1779
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:461
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition load.c:1455
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_NUM2SSIZE
Converts an instance of rb_cInteger into C's ssize_t.
Definition size_t.h:49
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
VALUE flags
Per-object flags.
Definition rbasic.h:81
Ruby's String.
Definition rstring.h:196
struct RBasic basic
Basic part, including flags and class.
Definition rstring.h:199
long len
Length of the string, not including terminating NUL character.
Definition rstring.h:206
Definition string.c:8222
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Blocks until the current thread obtains a lock.
Definition thread.c:308
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
ruby_value_type
C-level type of an object.
Definition value_type.h:113