Ruby 4.1.0dev (2026-11-12 revision acc624e47b178e3514d848a949f8e25d4e49e175)
re.c (acc624e47b178e3514d848a949f8e25d4e49e175)
1/**********************************************************************
2
3 re.c -
4
5 $Author$
6 created at: Mon Aug 9 18:24:49 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13
14#include <ctype.h>
15
16#include "encindex.h"
17#include "hrtime.h"
18#include "internal.h"
19#include "internal/bignum.h"
20#include "internal/encoding.h"
21#include "internal/error.h"
22#include "internal/gc.h"
23#include "internal/hash.h"
24#include "internal/imemo.h"
25#include "internal/re.h"
26#include "internal/string.h"
27#include "internal/object.h"
28#include "internal/ractor.h"
29#include "internal/variable.h"
30#include "regint.h"
31#include "ruby/atomic.h"
32#include "ruby/encoding.h"
33#include "ruby/re.h"
34#include "ruby/util.h"
35#include "ractor_core.h"
36
38 struct RRegexp re;
39 struct re_pattern_buffer pattern; /* a.k.a. OnigRegexType, defined in onigmo.h */
40};
41
42/* Flags of RRegexp
43 *
44 * 4: KCODE_FIXED
45 * The regexp has "fixed encoding", meaning it can't be match against any ASCII-compatible string.
46 * 5: RREGEXP_INITIALIZED
47 * The regexp has been fully initialized and can be used.
48 * 6: REG_ENCODING_NONE
49 * The regexp has no encoding. Means the `n` modifier was used.
50 * 10-16: ENCODING
51 * Stores the encoding of the regexp.
52 */
53
54#define KCODE_FIXED FL_USER4
55#define REG_ENCODING_NONE FL_USER6
56
57/* Flags of RMatch
58 *
59 * 0: MATCH_BUSY
60 * The match is currently in use or may have escaped and can no longer be recycled.
61 * 1: RMATCH_ONIG
62 * TBD.
63 * 2: RMATCH_OFFSETS_EXTERNAL
64 * The match layout isn't fully embedded, offsets are stored in an external buffer,
65 * which will need to be freed during sweep.
66 */
67
68#define MATCH_BUSY FL_USER0
69
70VALUE rb_eRegexpError, rb_eRegexpTimeoutError;
71
72typedef char onig_errmsg_buffer[ONIG_MAX_ERROR_MESSAGE_LEN];
73#define errcpy(err, msg) strlcpy((err), (msg), ONIG_MAX_ERROR_MESSAGE_LEN)
74
75#if 'a' == 97 /* it's ascii */
76static const char casetable[] = {
77 '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
78 '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
79 '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
80 '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
81 /* ' ' '!' '"' '#' '$' '%' '&' ''' */
82 '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
83 /* '(' ')' '*' '+' ',' '-' '.' '/' */
84 '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
85 /* '0' '1' '2' '3' '4' '5' '6' '7' */
86 '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
87 /* '8' '9' ':' ';' '<' '=' '>' '?' */
88 '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
89 /* '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' */
90 '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
91 /* 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' */
92 '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
93 /* 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' */
94 '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
95 /* 'X' 'Y' 'Z' '[' '\' ']' '^' '_' */
96 '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
97 /* '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' */
98 '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
99 /* 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' */
100 '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
101 /* 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' */
102 '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
103 /* 'x' 'y' 'z' '{' '|' '}' '~' */
104 '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
105 '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
106 '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
107 '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
108 '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
109 '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
110 '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
111 '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
112 '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
113 '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
114 '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
115 '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
116 '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
117 '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
118 '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
119 '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
120 '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
121};
122#else
123# error >>> "You lose. You will need a translation table for your character set." <<<
124#endif
125
126// The process-global timeout for regexp matching
127rb_hrtime_t rb_reg_match_time_limit = 0;
128
129int
130rb_memcicmp(const void *x, const void *y, rb_len_t len)
131{
132 const unsigned char *p1 = x, *p2 = y;
133 int tmp;
134
135 while (len--) {
136 if ((tmp = casetable[(unsigned)*p1++] - casetable[(unsigned)*p2++]))
137 return tmp;
138 }
139 return 0;
140}
141
142#if defined(HAVE_MEMMEM) && !defined(__APPLE__)
143static inline rb_len_t
144rb_memsearch_ss(const unsigned char *xs, rb_len_t m, const unsigned char *ys, rb_len_t n)
145{
146 const unsigned char *y;
147
148 if ((y = memmem(ys, n, xs, m)) != NULL)
149 return y - ys;
150 else
151 return -1;
152}
153#else
154static inline rb_len_t
155rb_memsearch_ss(const unsigned char *xs, rb_len_t m, const unsigned char *ys, rb_len_t n)
156{
157 const unsigned char *x = xs, *xe = xs + m;
158 const unsigned char *y = ys, *ye = ys + n;
159#define VALUE_MAX ((VALUE)~(VALUE)0)
160 VALUE hx, hy, mask = VALUE_MAX >> ((SIZEOF_VALUE - m) * CHAR_BIT);
161
162 if (m > SIZEOF_VALUE)
163 rb_bug("!!too long pattern string!!");
164
165 if (!(y = memchr(y, *x, n - m + 1)))
166 return -1;
167
168 /* Prepare hash value */
169 for (hx = *x++, hy = *y++; x < xe; ++x, ++y) {
170 hx <<= CHAR_BIT;
171 hy <<= CHAR_BIT;
172 hx |= *x;
173 hy |= *y;
174 }
175 /* Searching */
176 while (hx != hy) {
177 if (y == ye)
178 return -1;
179 hy <<= CHAR_BIT;
180 hy |= *y;
181 hy &= mask;
182 y++;
183 }
184 return y - ys - m;
185}
186#endif
187
188static inline rb_len_t
189rb_memsearch_qs(const unsigned char *xs, rb_len_t m, const unsigned char *ys, rb_len_t n)
190{
191 const unsigned char *x = xs, *xe = xs + m;
192 const unsigned char *y = ys;
193 VALUE i, qstable[256];
194
195 /* Preprocessing */
196 for (i = 0; i < 256; ++i)
197 qstable[i] = m + 1;
198 for (; x < xe; ++x)
199 qstable[*x] = xe - x;
200 /* Searching */
201 for (; y + m <= ys + n; y += *(qstable + y[m])) {
202 if (*xs == *y && memcmp(xs, y, m) == 0)
203 return y - ys;
204 }
205 return -1;
206}
207
208static inline unsigned int
209rb_memsearch_qs_utf8_hash(const unsigned char *x, const unsigned char *e)
210{
211 register const unsigned int mix = 8353;
212 register unsigned int h = *x;
213 if (h < 0xC0) {
214 return h + 256;
215 }
216 else if (e - x < (h < 0xE0 ? 2 : h < 0xF0 ? 3 : 4)) {
217 return h + 256;
218 }
219 else if (h < 0xE0) {
220 h *= mix;
221 h += x[1];
222 }
223 else if (h < 0xF0) {
224 h *= mix;
225 h += x[1];
226 h *= mix;
227 h += x[2];
228 }
229 else if (h < 0xF5) {
230 h *= mix;
231 h += x[1];
232 h *= mix;
233 h += x[2];
234 h *= mix;
235 h += x[3];
236 }
237 else {
238 return h + 256;
239 }
240 return (unsigned char)h;
241}
242
243static inline rb_len_t
244rb_memsearch_qs_utf8(const unsigned char *xs, rb_len_t m, const unsigned char *ys, rb_len_t n)
245{
246 const unsigned char *x = xs, *xe = xs + m;
247 const unsigned char *y = ys;
248 VALUE i, qstable[512];
249
250 /* Preprocessing */
251 for (i = 0; i < 512; ++i) {
252 qstable[i] = m + 1;
253 }
254 for (; x < xe; ++x) {
255 qstable[rb_memsearch_qs_utf8_hash(x, xe)] = xe - x;
256 }
257 /* Searching */
258 for (; y + m <= ys + n; y += qstable[rb_memsearch_qs_utf8_hash(y+m, ys+n)]) {
259 if (*xs == *y && memcmp(xs, y, m) == 0)
260 return y - ys;
261 }
262 return -1;
263}
264
265static inline rb_len_t
266rb_memsearch_with_char_size(const unsigned char *xs, rb_len_t m, const unsigned char *ys, rb_len_t n, int char_size)
267{
268 const unsigned char *x = xs, x0 = *xs, *y = ys;
269
270 for (n -= m; n >= 0; n -= char_size, y += char_size) {
271 if (x0 == *y && memcmp(x+1, y+1, m-1) == 0)
272 return y - ys;
273 }
274 return -1;
275}
276
277static inline rb_len_t
278rb_memsearch_wchar(const unsigned char *xs, rb_len_t m, const unsigned char *ys, rb_len_t n)
279{
280 return rb_memsearch_with_char_size(xs, m, ys, n, 2);
281}
282
283static inline rb_len_t
284rb_memsearch_qchar(const unsigned char *xs, rb_len_t m, const unsigned char *ys, rb_len_t n)
285{
286 return rb_memsearch_with_char_size(xs, m, ys, n, 4);
287}
288
290rb_memsearch(const void *x0, rb_len_t m, const void *y0, rb_len_t n, rb_encoding *enc)
291{
292 const unsigned char *x = x0, *y = y0;
293
294 if (m > n) return -1;
295 else if (m == n) {
296 return memcmp(x0, y0, m) == 0 ? 0 : -1;
297 }
298 else if (m < 1) {
299 return 0;
300 }
301 else if (m == 1) {
302 const unsigned char *ys = memchr(y, *x, n);
303
304 if (ys)
305 return ys - y;
306 else
307 return -1;
308 }
309 else if (LIKELY(rb_enc_mbminlen(enc) == 1)) {
310 if (m <= SIZEOF_VALUE) {
311 return rb_memsearch_ss(x0, m, y0, n);
312 }
313 else if (enc == rb_utf8_encoding()){
314 return rb_memsearch_qs_utf8(x0, m, y0, n);
315 }
316 }
317 else if (LIKELY(rb_enc_mbminlen(enc) == 2)) {
318 return rb_memsearch_wchar(x0, m, y0, n);
319 }
320 else if (LIKELY(rb_enc_mbminlen(enc) == 4)) {
321 return rb_memsearch_qchar(x0, m, y0, n);
322 }
323 return rb_memsearch_qs(x0, m, y0, n);
324}
325
326static int
327char_to_option(int c)
328{
329 int val;
330
331 switch (c) {
332 case 'i':
333 val = ONIG_OPTION_IGNORECASE;
334 break;
335 case 'x':
336 val = ONIG_OPTION_EXTEND;
337 break;
338 case 'm':
339 val = ONIG_OPTION_MULTILINE;
340 break;
341 default:
342 val = 0;
343 break;
344 }
345 return val;
346}
347
348enum { OPTBUF_SIZE = 4 };
349
350static char *
351option_to_str(char str[OPTBUF_SIZE], int options)
352{
353 char *p = str;
354 if (options & ONIG_OPTION_MULTILINE) *p++ = 'm';
355 if (options & ONIG_OPTION_IGNORECASE) *p++ = 'i';
356 if (options & ONIG_OPTION_EXTEND) *p++ = 'x';
357 *p = 0;
358 return str;
359}
360
361extern int
362rb_char_to_option_kcode(int c, int *option, int *kcode)
363{
364 *option = 0;
365
366 switch (c) {
367 case 'n':
368 *kcode = rb_ascii8bit_encindex();
369 return (*option = ARG_ENCODING_NONE);
370 case 'e':
371 *kcode = ENCINDEX_EUC_JP;
372 break;
373 case 's':
374 *kcode = ENCINDEX_Windows_31J;
375 break;
376 case 'u':
377 *kcode = rb_utf8_encindex();
378 break;
379 default:
380 *kcode = -1;
381 return (*option = char_to_option(c));
382 }
383 *option = ARG_ENCODING_FIXED;
384 return 1;
385}
386
387static bool
388reg_initialized_p(VALUE re)
389{
390 return FL_TEST_RAW(re, RREGEXP_INITIALIZED) && RREGEXP_SRC(re) && RREGEXP_SRC_PTR(re);
391}
392
393static void
394rb_reg_check(VALUE re)
395{
396 if (!reg_initialized_p(re)) {
397 rb_raise(rb_eTypeError, "uninitialized Regexp");
398 }
399}
400
401static void
402rb_reg_expr_str(VALUE str, const char *s, rb_len_t len,
403 rb_encoding *enc, rb_encoding *resenc, int term)
404{
405 const char *p, *pend;
406 int cr = ENC_CODERANGE_UNKNOWN;
407 int need_escape = 0;
408 int c, clen;
409
410 p = s; pend = p + len;
411 rb_str_coderange_scan_restartable(p, pend, enc, &cr);
412 if (rb_enc_asciicompat(enc) && ENC_CODERANGE_CLEAN_P(cr)) {
413 while (p < pend) {
414 c = rb_enc_ascget(p, pend, &clen, enc);
415 if (c == -1) {
416 if (enc == resenc) {
417 p += mbclen(p, pend, enc);
418 }
419 else {
420 need_escape = 1;
421 break;
422 }
423 }
424 else if (c != term && rb_enc_isprint(c, enc)) {
425 p += clen;
426 }
427 else {
428 need_escape = 1;
429 break;
430 }
431 }
432 }
433 else {
434 need_escape = 1;
435 }
436
437 if (!need_escape) {
438 rb_str_buf_cat(str, s, len);
439 }
440 else {
441 int unicode_p = rb_enc_unicode_p(enc);
442 p = s;
443 while (p<pend) {
444 c = rb_enc_ascget(p, pend, &clen, enc);
445 if (c == '\\' && p+clen < pend) {
446 int n = clen + mbclen(p+clen, pend, enc);
447 rb_str_buf_cat(str, p, n);
448 p += n;
449 continue;
450 }
451 else if (c == -1) {
452 clen = rb_enc_precise_mbclen(p, pend, enc);
453 if (!MBCLEN_CHARFOUND_P(clen)) {
454 c = (unsigned char)*p;
455 clen = 1;
456 goto hex;
457 }
458 if (resenc) {
459 unsigned int c = rb_enc_mbc_to_codepoint(p, pend, enc);
460 rb_str_buf_cat_escaped_char(str, c, unicode_p);
461 }
462 else {
463 clen = MBCLEN_CHARFOUND_LEN(clen);
464 rb_str_buf_cat(str, p, clen);
465 }
466 }
467 else if (c == term) {
468 char c = '\\';
469 rb_str_buf_cat(str, &c, 1);
470 rb_str_buf_cat(str, p, clen);
471 }
472 else if (rb_enc_isprint(c, enc)) {
473 rb_str_buf_cat(str, p, clen);
474 }
475 else if (!rb_enc_isspace(c, enc)) {
476 char b[8];
477
478 hex:
479 snprintf(b, sizeof(b), "\\x%02X", c);
480 rb_str_buf_cat(str, b, 4);
481 }
482 else {
483 rb_str_buf_cat(str, p, clen);
484 }
485 p += clen;
486 }
487 }
488}
489
490static VALUE
491rb_reg_desc(VALUE re)
492{
493 rb_encoding *enc = rb_enc_get(re);
494 VALUE str = rb_str_buf_new2("/");
495 rb_encoding *resenc = rb_default_internal_encoding();
496 if (resenc == NULL) resenc = rb_default_external_encoding();
497
498 if (re && rb_enc_asciicompat(enc)) {
499 rb_enc_copy(str, re);
500 }
501 else {
502 rb_enc_associate(str, rb_usascii_encoding());
503 }
504
505 VALUE src_str = RREGEXP_SRC(re);
506 rb_reg_expr_str(str, RSTRING_PTR(src_str), RSTRING_LEN(src_str), enc, resenc, '/');
507 RB_GC_GUARD(src_str);
508
509 rb_str_buf_cat2(str, "/");
510 if (re) {
511 char opts[OPTBUF_SIZE];
512 rb_reg_check(re);
513 if (*option_to_str(opts, RREGEXP_PTR(re)->options))
514 rb_str_buf_cat2(str, opts);
515 if (RBASIC(re)->flags & REG_ENCODING_NONE)
516 rb_str_buf_cat2(str, "n");
517 }
518 return str;
519}
520
521
522/*
523 * call-seq:
524 * source -> string
525 *
526 * Returns the original string of +self+:
527 *
528 * /ab+c/ix.source # => "ab+c"
529 *
530 * Regexp escape sequences are retained:
531 *
532 * /\x20\+/.source # => "\\x20\\+"
533 *
534 * Lexer escape characters are not retained:
535 *
536 * /\//.source # => "/"
537 *
538 */
539
540static VALUE
541rb_reg_source(VALUE re)
542{
543 VALUE str;
544
545 rb_reg_check(re);
546 str = rb_str_dup(RREGEXP_SRC(re));
547 return str;
548}
549
550/*
551 * call-seq:
552 * inspect -> string
553 *
554 * Returns a nicely-formatted string representation of +self+:
555 *
556 * /ab+c/ix.inspect # => "/ab+c/ix"
557 *
558 * Related: Regexp#to_s.
559 */
560
561static VALUE
562rb_reg_inspect(VALUE re)
563{
564 if (!reg_initialized_p(re)) {
565 return rb_any_to_s(re);
566 }
567 return rb_reg_desc(re);
568}
569
570static VALUE rb_reg_str_with_term(VALUE re, int term);
571
572/*
573 * call-seq:
574 * to_s -> string
575 *
576 * Returns a string showing the options and string of +self+:
577 *
578 * r0 = /ab+c/ix
579 * s0 = r0.to_s # => "(?ix-m:ab+c)"
580 *
581 * The returned string may be used as an argument to Regexp.new,
582 * or as interpolated text for a
583 * {Regexp interpolation}[rdoc-ref:Regexp@Interpolation+Mode]:
584 *
585 * r1 = Regexp.new(s0) # => /(?ix-m:ab+c)/
586 * r2 = /#{s0}/ # => /(?ix-m:ab+c)/
587 *
588 * Note that +r1+ and +r2+ are not equal to +r0+
589 * because their original strings are different:
590 *
591 * r0 == r1 # => false
592 * r0.source # => "ab+c"
593 * r1.source # => "(?ix-m:ab+c)"
594 *
595 * Related: Regexp#inspect.
596 *
597 */
598
599static VALUE
600rb_reg_to_s(VALUE re)
601{
602 return rb_reg_str_with_term(re, '/');
603}
604
605static VALUE
606rb_reg_str_with_term(VALUE re, int term)
607{
608 int options, opt;
609 const int embeddable = ONIG_OPTION_MULTILINE|ONIG_OPTION_IGNORECASE|ONIG_OPTION_EXTEND;
610 VALUE str = rb_str_buf_new2("(?");
611 char optbuf[OPTBUF_SIZE + 1]; /* for '-' */
612 rb_encoding *enc = rb_enc_get(re);
613
614 rb_reg_check(re);
615
616 rb_enc_copy(str, re);
617 options = RREGEXP_PTR(re)->options;
618 VALUE src_str = RREGEXP_SRC(re);
619 const UChar *ptr = (UChar *)RSTRING_PTR(src_str);
620 rb_len_t len = RSTRING_LEN(src_str);
621 again:
622 if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') {
623 int err = 1;
624 ptr += 2;
625 if ((len -= 2) > 0) {
626 do {
627 opt = char_to_option((int )*ptr);
628 if (opt != 0) {
629 options |= opt;
630 }
631 else {
632 break;
633 }
634 ++ptr;
635 } while (--len > 0);
636 }
637 if (len > 1 && *ptr == '-') {
638 ++ptr;
639 --len;
640 do {
641 opt = char_to_option((int )*ptr);
642 if (opt != 0) {
643 options &= ~opt;
644 }
645 else {
646 break;
647 }
648 ++ptr;
649 } while (--len > 0);
650 }
651 if (*ptr == ')') {
652 --len;
653 ++ptr;
654 goto again;
655 }
656 if (*ptr == ':' && ptr[len-1] == ')') {
657 Regexp *rp;
658 VALUE verbose = ruby_verbose;
660
661 ++ptr;
662 len -= 2;
663 err = onig_new(&rp, ptr, ptr + len, options,
664 enc, OnigDefaultSyntax, NULL);
665 onig_free(rp);
666 ruby_verbose = verbose;
667 }
668 if (err) {
669 options = RREGEXP_PTR(re)->options;
670 ptr = (UChar*)RREGEXP_SRC_PTR(re);
671 len = RREGEXP_SRC_LEN(re);
672 }
673 }
674
675 if (*option_to_str(optbuf, options)) rb_str_buf_cat2(str, optbuf);
676
677 if ((options & embeddable) != embeddable) {
678 optbuf[0] = '-';
679 option_to_str(optbuf + 1, ~options);
680 rb_str_buf_cat2(str, optbuf);
681 }
682
683 rb_str_buf_cat2(str, ":");
684 if (rb_enc_asciicompat(enc)) {
685 rb_reg_expr_str(str, (char*)ptr, len, enc, NULL, term);
686 rb_str_buf_cat2(str, ")");
687 }
688 else {
689 const char *s, *e;
690 char *paren;
691 ptrdiff_t n;
692 rb_str_buf_cat2(str, ")");
693 rb_enc_associate(str, rb_usascii_encoding());
694 str = rb_str_encode(str, rb_enc_from_encoding(enc), 0, Qnil);
695
696 /* backup encoded ")" to paren */
697 s = RSTRING_PTR(str);
698 e = RSTRING_END(str);
699 s = rb_enc_left_char_head(s, e-1, e, enc);
700 n = e - s;
701 paren = ALLOCA_N(char, n);
702 memcpy(paren, s, n);
703 rb_str_resize(str, RSTRING_LEN(str) - n);
704
705 rb_reg_expr_str(str, (char*)ptr, len, enc, NULL, term);
706 rb_str_buf_cat(str, paren, n);
707 }
708 rb_enc_copy(str, re);
709
710 RB_GC_GUARD(src_str);
711
712 return str;
713}
714
715NORETURN(static void rb_reg_raise(const char *err, VALUE re));
716
717static void
718rb_reg_raise(const char *err, VALUE re)
719{
720 VALUE desc = rb_reg_desc(re);
721
722 rb_raise(rb_eRegexpError, "%s: %"PRIsVALUE, err, desc);
723}
724
725static VALUE
726rb_enc_reg_error_desc(const char *s, rb_len_t len, rb_encoding *enc, int options, const char *err)
727{
728 char opts[OPTBUF_SIZE + 1]; /* for '/' */
729 VALUE desc = rb_str_buf_new2(err);
730 rb_encoding *resenc = rb_default_internal_encoding();
731 if (resenc == NULL) resenc = rb_default_external_encoding();
732
733 rb_enc_associate(desc, enc);
734 rb_str_buf_cat2(desc, ": /");
735 rb_reg_expr_str(desc, s, len, enc, resenc, '/');
736 opts[0] = '/';
737 option_to_str(opts + 1, options);
738 rb_str_buf_cat2(desc, opts);
739 return rb_exc_new3(rb_eRegexpError, desc);
740}
741
742NORETURN(static void rb_enc_reg_raise(const char *s, rb_len_t len, rb_encoding *enc, int options, const char *err));
743
744static void
745rb_enc_reg_raise(const char *s, rb_len_t len, rb_encoding *enc, int options, const char *err)
746{
747 rb_exc_raise(rb_enc_reg_error_desc(s, len, enc, options, err));
748}
749
750static VALUE
751rb_reg_error_desc(VALUE str, int options, const char *err)
752{
753 return rb_enc_reg_error_desc(RSTRING_PTR(str), RSTRING_LEN(str),
754 rb_enc_get(str), options, err);
755}
756
757NORETURN(static void rb_reg_raise_str(VALUE str, int options, const char *err));
758
759static void
760rb_reg_raise_str(VALUE str, int options, const char *err)
761{
762 rb_exc_raise(rb_reg_error_desc(str, options, err));
763}
764
765
766/*
767 * call-seq:
768 * casefold?-> true or false
769 *
770 * Returns +true+ if the case-insensitivity flag in +self+ is set,
771 * +false+ otherwise:
772 *
773 * /a/.casefold? # => false
774 * /a/i.casefold? # => true
775 * /(?i:a)/.casefold? # => false
776 *
777 */
778
779static VALUE
780rb_reg_casefold_p(VALUE re)
781{
782 rb_reg_check(re);
783 return RBOOL(RREGEXP_PTR(re)->options & ONIG_OPTION_IGNORECASE);
784}
785
786
787/*
788 * call-seq:
789 * options -> integer
790 *
791 * Returns an integer whose bits show the options set in +self+.
792 *
793 * The option bits are:
794 *
795 * Regexp::IGNORECASE # => 1
796 * Regexp::EXTENDED # => 2
797 * Regexp::MULTILINE # => 4
798 *
799 * Examples:
800 *
801 * /foo/.options # => 0
802 * /foo/i.options # => 1
803 * /foo/x.options # => 2
804 * /foo/m.options # => 4
805 * /foo/mix.options # => 7
806 *
807 * Note that additional bits may be set in the returned integer;
808 * these are maintained internally in +self+, are ignored if passed
809 * to Regexp.new, and may be ignored by the caller:
810 *
811 * Returns the set of bits corresponding to the options used when
812 * creating this regexp (see Regexp::new for details). Note that
813 * additional bits may be set in the returned options: these are used
814 * internally by the regular expression code. These extra bits are
815 * ignored if the options are passed to Regexp::new:
816 *
817 * r = /\xa1\xa2/e # => /\xa1\xa2/
818 * r.source # => "\\xa1\\xa2"
819 * r.options # => 16
820 * Regexp.new(r.source, r.options) # => /\xa1\xa2/
821 *
822 */
823
824static VALUE
825rb_reg_options_m(VALUE re)
826{
827 int options = rb_reg_options(re);
828 return INT2NUM(options);
829}
830
831static int
832reg_names_iter(const OnigUChar *name, const OnigUChar *name_end,
833 int back_num, int *back_refs, OnigRegex regex, void *arg)
834{
835 VALUE ary = (VALUE)arg;
836 rb_ary_push(ary, rb_enc_str_new((const char *)name, name_end-name, regex->enc));
837 return 0;
838}
839
840/*
841 * call-seq:
842 * names -> array_of_names
843 *
844 * Returns an array of names of captures
845 * (see {Named Captures}[rdoc-ref:Regexp@Named+Captures]):
846 *
847 * /(?<foo>.)(?<bar>.)(?<baz>.)/.names # => ["foo", "bar", "baz"]
848 * /(?<foo>.)(?<foo>.)/.names # => ["foo"]
849 * /(.)(.)/.names # => []
850 *
851 */
852
853static VALUE
854rb_reg_names(VALUE re)
855{
856 VALUE ary;
857 rb_reg_check(re);
858 ary = rb_ary_new_capa(onig_number_of_names(RREGEXP_PTR(re)));
859 onig_foreach_name(RREGEXP_PTR(re), reg_names_iter, (void*)ary);
860 return ary;
861}
862
863static int
864reg_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
865 int back_num, int *back_refs, OnigRegex regex, void *arg)
866{
867 VALUE hash = (VALUE)arg;
868 VALUE ary = rb_ary_new2(back_num);
869 int i;
870
871 for (i = 0; i < back_num; i++)
872 rb_ary_store(ary, i, INT2NUM(back_refs[i]));
873
874 rb_hash_aset(hash, rb_str_new((const char*)name, name_end-name),ary);
875
876 return 0;
877}
878
879/*
880 * call-seq:
881 * named_captures -> hash
882 *
883 * Returns a hash representing named captures of +self+
884 * (see {Named Captures}[rdoc-ref:Regexp@Named+Captures]):
885 *
886 * - Each key is the name of a named capture.
887 * - Each value is an array of integer indexes for that named capture.
888 *
889 * Examples:
890 *
891 * /(?<foo>.)(?<bar>.)/.named_captures # => {"foo"=>[1], "bar"=>[2]}
892 * /(?<foo>.)(?<foo>.)/.named_captures # => {"foo"=>[1, 2]}
893 * /(.)(.)/.named_captures # => {}
894 *
895 */
896
897static VALUE
898rb_reg_named_captures(VALUE re)
899{
900 regex_t *reg = (rb_reg_check(re), RREGEXP_PTR(re));
901 VALUE hash = rb_hash_new_capa(onig_number_of_names(reg));
902 onig_foreach_name(reg, reg_named_captures_iter, (void*)hash);
903 return hash;
904}
905
906static int
907onig_new_with_source(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
908 OnigOptionType option, OnigEncoding enc, const OnigSyntaxType* syntax,
909 OnigErrorInfo* einfo, const char *sourcefile, int sourceline)
910{
911 int r;
912
913 if (IS_NULL(reg)) return ONIGERR_MEMORY;
914
915 r = onig_reg_init(reg, option, ONIGENC_CASE_FOLD_DEFAULT, enc, syntax);
916 if (r) goto err;
917
918 r = onig_compile_ruby(reg, pattern, pattern_end, einfo, sourcefile, sourceline);
919 if (r) {
920 err:
921 onig_free_body(reg);
922 }
923 return r;
924}
925
926static bool
927make_regexp(Regexp *rp, const char *s, rb_len_t len, rb_encoding *enc, int flags, onig_errmsg_buffer err,
928 const char *sourcefile, int sourceline)
929{
930 int r;
931 OnigErrorInfo einfo;
932
933 /* Handle escaped characters first. */
934
935 /* Build a copy of the string (in dest) with the
936 escaped characters translated, and generate the regex
937 from that.
938 */
939
940 r = onig_new_with_source(rp, (UChar*)s, (UChar*)(s + len), flags,
941 enc, OnigDefaultSyntax, &einfo, sourcefile, sourceline);
942 if (r) {
943 onig_error_code_to_str((UChar*)err, r, &einfo);
944 return false;
945 }
946 return true;
947}
948
949
950/*
951 * Document-class: MatchData
952 *
953 * :markup: markdown
954 *
955 * Ruby [matcher methods][matcher methods] create \MatchData objects.
956 *
957 * A \MatchData object contains the detailed result of a match, including:
958 *
959 * - The target string used for the match.
960 * - The Regexp used for the match.
961 * - The matched substring.
962 * - The substring preceding the matched substring.
963 * - The substring following the matched substring.
964 * - Captured substrings.
965 *
966 * ## In Brief
967 *
968 * ```ruby
969 * # Basics.
970 * s = 'https://docs.ruby-lang.org/en/2.5.0/MatchData.html'
971 * m = s.match(/(\d\.?)+/) # => #<MatchData "2.5.0" 1:"0">
972 * m.string # => "https://docs.ruby-lang.org/en/2.5.0/MatchData.html"
973 * m.regexp # => /(\d\.?)+/
974 * m[0] # => "2.5.0" # Matched substring.
975 * m.pre_match # => "https://docs.ruby-lang.org/en/"
976 * m.post_match # => "/MatchData.html"
977 *
978 * # Unnamed (numbered) captures.
979 * m = "2025-12-25".match(/(\d{4})-(\d{2})-(\d{2})/)
980 * # => #<MatchData "2025-12-25" 1:"2025" 2:"12" 3:"25">
981 * m[0] # => "2025-12-25" # Entire matched substring.
982 * m[1] # => "2025" # First captured substring.
983 * m[2] # => "12" # Second captured substring.
984 * m[3] # => "25" # Third captured substring.
985 * m[4] # => nil # No more captured substrings.
986 *
987 * # Named captures.
988 * m = "2025-12-25".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/)
989 * m[:year] # "2025"
990 * m[:month] # "12"
991 * m[:day] # "25"
992 * # Also available by numbers.
993 * m[0] # => "2025-12-25"
994 * m[1] # => "2025"
995 * m[:nosuch] # Raises IndexError: undefined group name reference: nosuch.
996 * ```
997 *
998 * ## Matcher Methods
999 *
1000 * Each of these methods creates a \MatchData object,
1001 * updates the [matcher global variables][matcher global variables],
1002 * and returns the \MatchData object:
1003 *
1004 * - Regexp#match.
1005 * - String#match.
1006 * - Symbol#match.
1007 *
1008 * Each of these methods creates a \MatchData object,
1009 * updates the [matcher global variables][matcher global variables],
1010 * but _does not_ return the \MatchData object;
1011 * the \MatchData object is available in global variable `$~`:
1012 *
1013 * - Regexp#=~
1014 * - String#=~
1015 * - String#gsub
1016 * - String#gsub!
1017 * - String#scan
1018 * - String#sub
1019 * - String#sub!
1020 * - Symbol#=~
1021 *
1022 * Each of these methods, when called with a Regexp argument,
1023 * creates a \MatchData object,
1024 * updates the [matcher global variables][matcher global variables],
1025 * but _does not_ return the \MatchData object;
1026 * the \MatchData object is available in global variable `$~`:
1027 *
1028 * - String#index
1029 * - String#partition
1030 * - String#rindex
1031 * - String#rpartition
1032 * - String#slice
1033 * - String#slice!
1034 * - String#split
1035 *
1036 * ## Match-Related Methods
1037 *
1038 * Each of these predicate methods performs a "fast match,"
1039 * returning whether a match was found,
1040 * but _not_ creating a \MatchData object,
1041 * and _not_ setting [matcher global variables][matcher global variables]:
1042 *
1043 * - Regexp#match?
1044 * - String#match?
1045 * - Symbol#match?
1046 *
1047 * This method return the \MatchData object resulting from the most recent match:
1048 *
1049 * - Regexp::last_match.
1050 *
1051 * [matcher methods]: rdoc-ref:MatchData@Matcher+Methods
1052 * [matcher global variables]: rdoc-ref:Regexp@Global+Variables
1053 *
1054 *
1055 * ## What's Here
1056 *
1057 * First, what's elsewhere. Class \MatchData:
1058 *
1059 * - Inherits from {class Object}[rdoc-ref:Object@Whats-Here].
1060 *
1061 * Here, class \MatchData provides methods that are useful for:
1062 *
1063 * ### General Methods
1064 *
1065 * - #== (aliased as #eql?): returns whether `self` and another object are equal.
1066 * - #hash: returns the integer hash value for `self`.
1067 * - #inspect: returns a string representation of `self`.
1068 * - #post_match: returns the substring that follows the matched string.
1069 * - #pre_match: returns the substring that precedes the matched string.
1070 * - #regexp: returns the Regexp used to produce `self`.
1071 * - #size (aliased as #length): returns the size of the array of matched substrings.
1072 * - #string: returns the string used to produce `self`.
1073 * - #to_a: returns the array of matched substrings.
1074 * - #to_s: returns a string representation of `self`.
1075 *
1076 * ### Capture Methods
1077 *
1078 * Each of these methods returns information about all captures:
1079 *
1080 * - #captures (aliased as #deconstruct): returns an array of the captured substrings.
1081 * - #named_captures: returns a hash of the named captures.
1082 * - #names: returns an array of the capture names.
1083 *
1084 * Each of these methods returns information about one capture,
1085 * which may be specified by its integer index or by its name (if it is a named capture):
1086 *
1087 * - #[]: returns a matched substring or an array of matched substrings
1088 * for the given arguments.
1089 * - #begin: returns the character offset of the beginning of the capture.
1090 * - #bytebegin: returns the byte offset of the beginning of the capture.
1091 * - #byteend: returns the byte offset of the end of the capture.
1092 * - #byteoffset: returns the byte offsets of the beginning and end of the capture.
1093 * - #deconstruct_keys: returns a hash of the names and values for the given names.
1094 * - #end: returns the character offset of the end of the capture.
1095 * - #integer_at: returns the value of the capture, converted to an integer.
1096 * - #match: returns the matched substring for the capture.
1097 * - #match_length: returns the length (in characters) of the matched substring for the capture.
1098 * - #offset: returns the begin and end offsets for the capture.
1099 * - #values_at: returns a matched substring or an array of matched substrings
1100 * for the given arguments.
1101 *
1102 */
1103
1105
1106static VALUE
1107match_alloc_n(VALUE klass, int num_regs)
1108{
1109 int capa = num_regs * 2;
1110 size_t alloc_size = offsetof(struct RMatch, as) + sizeof(OnigPosition) * capa;
1111 if (alloc_size < sizeof(struct RMatch)) {
1112 alloc_size = sizeof(struct RMatch);
1113 }
1114
1115 VALUE flags = T_MATCH;
1116 if (!rb_gc_size_allocatable_p(alloc_size)) {
1117 alloc_size = sizeof(struct RMatch);
1118 flags |= RMATCH_ONIG;
1119 capa = 0;
1120 }
1121
1122 NEWOBJ_OF(match, struct RMatch, klass, flags, alloc_size);
1123 memset(((char *)match) + sizeof(struct RBasic), 0, alloc_size - sizeof(struct RBasic));
1124 match->capa = capa;
1125 return (VALUE)match;
1126}
1127
1128static VALUE
1129match_alloc(VALUE klass)
1130{
1131 return match_alloc_n(klass, 0);
1132}
1133
1134int
1135rb_reg_region_copy(struct re_registers *to, const struct re_registers *from)
1136{
1137 onig_region_copy(to, (OnigRegion *)from);
1138 if (to->allocated) return 0;
1139 rb_gc();
1140 onig_region_copy(to, (OnigRegion *)from);
1141 if (to->allocated) return 0;
1142 return ONIGERR_MEMORY;
1143}
1144
1145static void
1146match_to_onig(VALUE match, int num_regs, const OnigPosition *src_beg, const OnigPosition *src_end)
1147{
1148 struct RMatch *rm = RMATCH(match);
1149 struct re_registers tmp = {0};
1150 if (onig_region_resize(&tmp, num_regs)) {
1151 rb_memerror();
1152 }
1153 memcpy(tmp.beg, src_beg, num_regs * sizeof(OnigPosition));
1154 memcpy(tmp.end, src_end, num_regs * sizeof(OnigPosition));
1155 rm->as.onig = tmp;
1156 FL_SET_RAW(match, RMATCH_ONIG);
1157}
1158
1159void
1160rb_match_ensure_onig(VALUE match)
1161{
1162 if (FL_TEST_RAW(match, RMATCH_ONIG)) return;
1163 struct RMatch *rm = RMATCH(match);
1164 int n = rm->num_regs;
1165 match_to_onig(match, n, &rm->as.embed[0], &rm->as.embed[n]);
1166}
1167
1168/* Replace `match`'s registers with a copy of (num_regs, beg, end). If the
1169 * data does not fit in the embed form, the match is evicted to onig form.
1170 * Raises on OOM. */
1171static void
1172match_set_regs(VALUE match, int num_regs, const OnigPosition *beg, const OnigPosition *end)
1173{
1174 struct RMatch *rm = RMATCH(match);
1175
1176 if (FL_TEST_RAW(match, RMATCH_ONIG)) {
1177 if (onig_region_resize(&rm->as.onig, num_regs)) {
1178 rb_memerror();
1179 }
1180 memcpy(rm->as.onig.beg, beg, num_regs * sizeof(OnigPosition));
1181 memcpy(rm->as.onig.end, end, num_regs * sizeof(OnigPosition));
1182 }
1183 else if (num_regs * 2 <= rm->capa) {
1184 memcpy(&rm->as.embed[0], beg, num_regs * sizeof(OnigPosition));
1185 memcpy(&rm->as.embed[num_regs], end, num_regs * sizeof(OnigPosition));
1186 }
1187 else {
1188 match_to_onig(match, num_regs, beg, end);
1189 }
1190 rm->num_regs = num_regs;
1191}
1192
1193/* Helpers for carrying a MatchData to another objspace via Ractor#send(move:). The match's
1194 * registers are written out to an onig-independent blob so the original malloc'd area can be
1195 * freed, leaving an empty shell behind, and rebuilt from the blob on the receiving side. */
1196void *
1197rb_match_blob_dump(VALUE match, VALUE *regexp_out, VALUE *str_out, int *num_regs_out, bool release_source)
1198{
1199 struct RMatch *rm = RMATCH(match);
1200 int n = rm->num_regs;
1201 *regexp_out = rm->regexp;
1202 *str_out = rm->str;
1203 *num_regs_out = n;
1204
1205 OnigPosition *blob = ALLOC_N(OnigPosition, n ? 2 * n : 1);
1206 const OnigPosition *beg = RMATCH_BEG_PTR(match);
1207 const OnigPosition *end = RMATCH_END_PTR(match);
1208 for (int i = 0; i < n; i++) {
1209 blob[2 * i] = beg[i];
1210 blob[2 * i + 1] = end[i];
1211 }
1212
1213 /* A copy leaves the source usable; only a move takes its internals apart. */
1214 if (release_source) {
1215 if (FL_TEST_RAW(match, RMATCH_ONIG)) {
1216 onig_region_free(&rm->as.onig, 0);
1217 memset(&rm->as.onig, 0, sizeof(rm->as.onig));
1218 FL_UNSET_RAW(match, RMATCH_ONIG);
1219 }
1220 if (rm->char_offset) {
1221 ruby_xfree(rm->char_offset);
1222 rm->char_offset = NULL;
1224 }
1225 }
1226 return blob;
1227}
1228
1229VALUE
1230rb_match_blob_alloc(VALUE klass, int num_regs)
1231{
1232 return match_alloc_n(klass, num_regs);
1233}
1234
1235void
1236rb_match_blob_load(VALUE match, VALUE regexp, VALUE str, int num_regs, const void *blob_)
1237{
1238 const OnigPosition *blob = blob_;
1239 struct RMatch *rm = RMATCH(match);
1240 RB_OBJ_WRITE(match, &rm->str, str);
1241 RB_OBJ_WRITE(match, &rm->regexp, regexp);
1242
1243 OnigPosition *beg = ALLOC_N(OnigPosition, num_regs ? num_regs : 1);
1244 OnigPosition *end = ALLOC_N(OnigPosition, num_regs ? num_regs : 1);
1245 for (int i = 0; i < num_regs; i++) {
1246 beg[i] = blob[2 * i];
1247 end[i] = blob[2 * i + 1];
1248 }
1249 match_set_regs(match, num_regs, beg, end);
1250 ruby_xfree(beg);
1251 ruby_xfree(end);
1252}
1253
1254void
1255rb_match_blob_free(void *blob)
1256{
1257 ruby_xfree(blob);
1258}
1259
1260typedef struct {
1261 rb_len_t byte_pos;
1262 rb_len_t char_pos;
1263} pair_t;
1264
1265static int
1266pair_byte_cmp(const void *pair1, const void *pair2)
1267{
1268 rb_len_t diff = ((pair_t*)pair1)->byte_pos - ((pair_t*)pair2)->byte_pos;
1269#if SIZEOF_RB_LEN_T > SIZEOF_INT
1270 return diff ? diff > 0 ? 1 : -1 : 0;
1271#else
1272 return (int)diff;
1273#endif
1274}
1275
1276static void
1277update_char_offset(VALUE match)
1278{
1279 struct RMatch *rm = RMATCH(match);
1280 int i, num_regs, num_pos;
1281 rb_len_t c;
1282 char *s, *p, *q;
1283 rb_encoding *enc;
1284 pair_t *pairs;
1285 VALUE pairs_obj = Qnil;
1286
1288 return;
1289
1290 num_regs = RMATCH_NREGS(match);
1291
1293 SIZED_REALLOC_N(rm->char_offset, struct rmatch_offset, num_regs, rm->char_offset_num_allocated);
1295 FL_SET_RAW(match, RMATCH_OFFSETS_EXTERNAL);
1296 }
1297
1298 enc = rb_enc_get(RMATCH(match)->str);
1299 if (rb_enc_mbmaxlen(enc) == 1) {
1300 for (i = 0; i < num_regs; i++) {
1301 rm->char_offset[i].beg = RMATCH_BEG(match, i);
1302 rm->char_offset[i].end = RMATCH_END(match, i);
1303 }
1304 return;
1305 }
1306
1307 pairs = RB_ALLOCV_N(pair_t, pairs_obj, num_regs * 2);
1308 num_pos = 0;
1309 for (i = 0; i < num_regs; i++) {
1310 if (RMATCH_BEG(match, i) < 0)
1311 continue;
1312 pairs[num_pos++].byte_pos = RMATCH_BEG(match, i);
1313 pairs[num_pos++].byte_pos = RMATCH_END(match, i);
1314 }
1315 qsort(pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
1316
1317 s = p = RSTRING_PTR(RMATCH(match)->str);
1318 c = 0;
1319 for (i = 0; i < num_pos; i++) {
1320 q = s + pairs[i].byte_pos;
1321 c += rb_enc_strlen(p, q, enc);
1322 pairs[i].char_pos = c;
1323 p = q;
1324 }
1325
1326 for (i = 0; i < num_regs; i++) {
1327 pair_t key, *found;
1328 if (RMATCH_BEG(match, i) < 0) {
1329 rm->char_offset[i].beg = -1;
1330 rm->char_offset[i].end = -1;
1331 continue;
1332 }
1333
1334 key.byte_pos = RMATCH_BEG(match, i);
1335 found = bsearch(&key, pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
1336 rm->char_offset[i].beg = found->char_pos;
1337
1338 key.byte_pos = RMATCH_END(match, i);
1339 found = bsearch(&key, pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
1340 rm->char_offset[i].end = found->char_pos;
1341 }
1342
1343 RB_ALLOCV_END(pairs_obj);
1344}
1345
1346static VALUE
1347match_check(VALUE match)
1348{
1349 if (!RMATCH(match)->regexp) {
1350 rb_raise(rb_eTypeError, "uninitialized MatchData");
1351 }
1352 return match;
1353}
1354
1355/* :nodoc: */
1356VALUE
1357rb_match_init_copy(VALUE obj, VALUE orig)
1358{
1359 struct RMatch *rm = RMATCH(obj);
1360
1361 if (!OBJ_INIT_COPY(obj, orig)) return obj;
1362
1363 RB_OBJ_WRITE(obj, &rm->str, RMATCH(orig)->str);
1364 RB_OBJ_WRITE(obj, &rm->regexp, RMATCH(orig)->regexp);
1365
1366 match_set_regs(obj, RMATCH_NREGS(orig), RMATCH_BEG_PTR(orig), RMATCH_END_PTR(orig));
1367
1368 if (RMATCH(orig)->char_offset_num_allocated) {
1369 if (rm->char_offset_num_allocated < rm->num_regs) {
1370 SIZED_REALLOC_N(rm->char_offset, struct rmatch_offset, rm->num_regs, rm->char_offset_num_allocated);
1372 FL_SET_RAW(obj, RMATCH_OFFSETS_EXTERNAL);
1373 }
1375 struct rmatch_offset, rm->num_regs);
1376 RB_GC_GUARD(orig);
1377 }
1378
1379 return obj;
1380}
1381
1382
1383/*
1384 * :markup: markdown
1385 *
1386 * call-seq:
1387 * regexp -> regexp
1388 *
1389 * Returns the Regexp that produced the match:
1390 *
1391 * ```ruby
1392 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1393 * match = '2026-12-25'.match(regexp)
1394 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1395 * match.regexp
1396 * # => /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1397 * ```
1398 *
1399 */
1400
1401static VALUE
1402match_regexp(VALUE match)
1403{
1404 VALUE regexp;
1405 match_check(match);
1406 regexp = RMATCH(match)->regexp;
1407 if (NIL_P(regexp)) {
1408 VALUE str = rb_reg_nth_match(0, match);
1410 RB_OBJ_WRITE(match, &RMATCH(match)->regexp, regexp);
1411 }
1412 return regexp;
1413}
1414
1415/*
1416 * :markup: markdown
1417 *
1418 * call-seq:
1419 * names -> array_of_strings
1420 *
1421 * Returns an array containing the capture names:
1422 *
1423 * ```ruby
1424 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1425 * match = '2026-12-25'.match(regexp)
1426 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1427 * match.names # => ["year", "month", "day"]
1428 * ```
1429 *
1430 */
1431
1432static VALUE
1433match_names(VALUE match)
1434{
1435 match_check(match);
1436 if (NIL_P(RMATCH(match)->regexp))
1437 return rb_ary_new_capa(0);
1438 return rb_reg_names(RMATCH(match)->regexp);
1439}
1440
1441/*
1442 * :markup: markdown
1443
1444 * call-seq:
1445 * size -> integer
1446 *
1447 * Returns size of the match array:
1448 *
1449 * ```ruby
1450 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1451 * match = '2026-12-25'.match(regexp)
1452 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1453 * match.size # => 4
1454 * ```
1455 *
1456 */
1457
1458static VALUE
1459match_size(VALUE match)
1460{
1461 match_check(match);
1462 return INT2FIX(RMATCH_NREGS(match));
1463}
1464
1465static int match_name_to_backref_number(VALUE match, VALUE name);
1466NORETURN(static void name_to_backref_error(VALUE name));
1467
1468static void
1469name_to_backref_error(VALUE name)
1470{
1471 rb_raise(rb_eIndexError, "undefined group name reference: % "PRIsVALUE,
1472 name);
1473}
1474
1475static void
1476backref_number_check(VALUE match, int i)
1477{
1478 if (i < 0 || RMATCH_NREGS(match) <= i)
1479 rb_raise(rb_eIndexError, "index %d out of matches", i);
1480}
1481
1482static int
1483match_backref_number(VALUE match, VALUE backref)
1484{
1485 int num;
1486
1487 match_check(match);
1488 if (SYMBOL_P(backref)) {
1489 backref = rb_sym2str(backref);
1490 }
1491 else if (!RB_TYPE_P(backref, T_STRING)) {
1492 return NUM2INT(backref);
1493 }
1494
1495 num = match_name_to_backref_number(match, backref);
1496
1497 if (num < 1) {
1498 name_to_backref_error(backref);
1499 }
1500
1501 return num;
1502}
1503
1504int
1506{
1507 return match_backref_number(match, backref);
1508}
1509
1510/*
1511 * :markup: markdown
1512 *
1513 * call-seq:
1514 * offset(n) -> [begin_offset, end_offset]
1515 * offset(name) -> [begin_offset, end_offset]
1516 *
1517 * Returns the offsets (in characters) of the beginning (#begin value)
1518 * and end (#end value) of the specified match.
1519 *
1520 * With non-negative integer argument `n` given,
1521 * returns the character offsets for the `n`th match:
1522 *
1523 * ```ruby
1524 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1525 * match = '2026-12-25'.match(regexp)
1526 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1527 * match[0] # => "2026-12-25"
1528 * match.offset(0) # => [0, 10]
1529 * match[2] # => "12"
1530 * match.offset(2) # => [5, 7]
1531 * match.offset(4) # Raises IndexError: index 4 out of matches.
1532 *
1533 * match = /(ん)(に)(ち)/.match('こんにちは')
1534 * # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
1535 * match[0] # => "んにち"
1536 * match.offset(0) # => [1, 4]
1537 * match[2] # => "に"
1538 * match.offset(2) # => [2, 3]
1539 * match.offset(4) # Raises IndexError: index 4 out of matches.
1540 * ```
1541 *
1542 * With string or symbol argument `name` given,
1543 * returns the offsets for the named match:
1544 *
1545 * ```ruby
1546 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1547 * match = '2026-12-25'.match(regexp)
1548 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1549 * match[:year] # => "2026"
1550 * match.offset(:year) # => [0, 4]
1551 * match['day'] # => "25"
1552 * match.offset('day') # => [8, 10]
1553 * match.offset(:nosuch) # Raises IndexError: undefined group name reference: nosuch.
1554 * ```
1555 *
1556 */
1557
1558static VALUE
1559match_offset(VALUE match, VALUE n)
1560{
1561 int i = match_backref_number(match, n);
1562
1563 match_check(match);
1564 backref_number_check(match, i);
1565
1566 if (RMATCH_BEG(match, i) < 0)
1567 return rb_assoc_new(Qnil, Qnil);
1568
1569 update_char_offset(match);
1570 return rb_assoc_new(LEN2NUM(RMATCH(match)->char_offset[i].beg),
1571 LEN2NUM(RMATCH(match)->char_offset[i].end));
1572}
1573
1574/*
1575 * :markup: markdown
1576 *
1577 * call-seq:
1578 * byteoffset(object) -> [bytebegin, byteend]
1579 *
1580 * Returns the offsets (in bytes) of the beginning and end of the specified match.
1581 *
1582 * With argument `object` given as a non-negative integer argument `n` given,
1583 * returns the offsets of the `n`th match:
1584 *
1585 * ```ruby
1586 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1587 * match = '2026-12-25'.match(regexp)
1588 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1589 * match[1] # => "2026"
1590 * match.byteoffset(1) # => [0, 4]
1591 * match[3] # => "25"
1592 * match.byteoffset(3) # => [8, 10]
1593 * match.byteoffset(10) # Raises IndexError: index 10 out of matches.
1594 *
1595 * match = /(ん)(に)(ち)/.match('こんにちは')
1596 * # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
1597 * match[1] # => "ん"
1598 * match.byteoffset(1) # => [3, 6] # Byte offsets.
1599 * match.offset(1) # => [1, 2] # Character offsets.
1600 * ```
1601 *
1602 * With argument `object` given as a string or symbol argument `name`,
1603 * returns the offsets of the named match:
1604 *
1605 * ```ruby
1606 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1607 * match = '2026-12-25'.match(regexp)
1608 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1609 * match[:year] # => "2026"
1610 * match.byteoffset(:year) # => [0, 4]
1611 * match.byteoffset('day') # => [8, 10]
1612 * ```
1613 *
1614 *
1615 * Related: MatchData#offset.
1616 *
1617 */
1618
1619static VALUE
1620match_byteoffset(VALUE match, VALUE n)
1621{
1622 int i = match_backref_number(match, n);
1623
1624 match_check(match);
1625 backref_number_check(match, i);
1626
1627 if (RMATCH_BEG(match, i) < 0)
1628 return rb_assoc_new(Qnil, Qnil);
1629 return rb_assoc_new(LEN2NUM(RMATCH_BEG(match, i)), LEN2NUM(RMATCH_END(match, i)));
1630}
1631
1632
1633/*
1634 * :markup: markdown
1635 *
1636 * call-seq:
1637 * bytebegin(n) -> integer
1638 * bytebegin(name) -> integer
1639 *
1640 * Returns the offset (in bytes) of the beginning of the specified match.
1641 *
1642 * With non-negative integer argument `n` given,
1643 * returns the offset of the beginning of the `n`th match:
1644 *
1645 * ```ruby
1646 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1647 * match = '2026-12-25'.match(regexp)
1648 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1649 * match[0] # => "2026-12-25"
1650 * match.bytebegin(0) # => 0
1651 * match[2] # => "12"
1652 * match.bytebegin(2) # => 5
1653 * match.bytebegin(20) # Raises IndexError: index 20 out of matches.
1654 *
1655 * match = /(ん)(に)(ち)/.match('こんにちは')
1656 * # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
1657 * match[2] # => "に"
1658 * match.bytebegin(2) # => 6 # Byte offset.
1659 * match.begin(2) # => 2 # Character offset.
1660 * ```
1661 *
1662 * With string or symbol argument `name` given,
1663 * returns the offset of the beginning for the named match:
1664 *
1665 * ```ruby
1666 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1667 * match = '2026-12-25'.match(regexp)
1668 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1669 * match[:month] # => "12"
1670 * match.bytebegin(:month) # => 5
1671 * match.bytebegin('day') # => 8
1672 * ```
1673 *
1674 * Related: MatchData#begin.
1675 *
1676 */
1677
1678static VALUE
1679match_bytebegin(VALUE match, VALUE n)
1680{
1681 int i = match_backref_number(match, n);
1682
1683 match_check(match);
1684 backref_number_check(match, i);
1685
1686 if (RMATCH_BEG(match, i) < 0)
1687 return Qnil;
1688 return LEN2NUM(RMATCH_BEG(match, i));
1689}
1690
1691
1692/*
1693 * :markup: markdown
1694 *
1695 * call-seq:
1696 * byteend(n) -> integer
1697 * byteend(name) -> integer
1698 *
1699 * Returns the offset (in bytes) of the end of the specified match.
1700 *
1701 * When non-negative integer argument `n` is given,
1702 * returns the offset of the end of the `n`th match:
1703 *
1704 * ```ruby
1705 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1706 * match = '2026-12-25'.match(regexp)
1707 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1708 * match[1] # => "2026"
1709 * match.byteend(1) # => 4
1710 * match[3] # => "25"
1711 * match.byteend(3) # => 10
1712 * match.byteend(4) # Raises IndexError: index 4 out of matches.
1713 *
1714 * match = /(ん)(に)(ち)/.match('こんにちは')
1715 * # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
1716 * match[1] # => "ん"
1717 * match.byteend(1) # => 6 # Byte offset.
1718 * match.end(1) # => 2 # Character offset.
1719 * ```
1720 *
1721 * When string or symbol argument `name` is given,
1722 * returns the offset of the end for the named match:
1723 *
1724 * ```ruby
1725 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1726 * match = '2026-12-25'.match(regexp)
1727 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1728 * match[:year] # => "2026"
1729 * match.byteend(:year) # => 4
1730 * match['day'] # => "25"
1731 * match.byteend('day') # => 10
1732 * ```
1733 *
1734 * Related: MatchData#bytebegin.
1735 *
1736 */
1737
1738static VALUE
1739match_byteend(VALUE match, VALUE n)
1740{
1741 int i = match_backref_number(match, n);
1742
1743 match_check(match);
1744 backref_number_check(match, i);
1745
1746 if (RMATCH_BEG(match, i) < 0)
1747 return Qnil;
1748 return LEN2NUM(RMATCH_END(match, i));
1749}
1750
1751
1752/*
1753 * :markup: markdown
1754 *
1755 * call-seq:
1756 * begin(n) -> integer
1757 * begin(name) -> integer
1758 *
1759 * Returns the offset (in characters) of the beginning of the specified match.
1760 *
1761 * With non-negative integer argument `n` given,
1762 * returns the character offset of the beginning of the `n`th match:
1763 *
1764 * ```ruby
1765 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1766 * match = '2026-12-25'.match(regexp)
1767 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1768 * match[0] # => "2026-12-25"
1769 * match.begin(0) # => 0
1770 * match[3] # => "25"
1771 * match.begin(3) # => 8
1772 * match.begin(10) # Raises IndexError: index 10 out of matches.
1773 *
1774 * match = /(ん)(に)(ち)/.match('こんにちは')
1775 * # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
1776 * match[2] # => "に"
1777 * match.begin(2) # => 2 # Character offset.
1778 * match.bytebegin(2) # => 6 # Byte offset.
1779 * ```
1780 *
1781 * With string or symbol argument `name` given,
1782 * returns the offset of the beginning for the named match:
1783 *
1784 * ```ruby
1785 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1786 * match = '2026-12-25'.match(regexp)
1787 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1788 * match[:year] # => "2026"
1789 * match.begin(:year) # => 0
1790 * match.begin('month') # => 5
1791 * ```
1792 *
1793 * Related: MatchData#bytebegin.
1794 *
1795 */
1796
1797static VALUE
1798match_begin(VALUE match, VALUE n)
1799{
1800 int i = match_backref_number(match, n);
1801
1802 match_check(match);
1803 backref_number_check(match, i);
1804
1805 if (RMATCH_BEG(match, i) < 0)
1806 return Qnil;
1807
1808 update_char_offset(match);
1809 return LEN2NUM(RMATCH(match)->char_offset[i].beg);
1810}
1811
1812
1813/*
1814 * :markup: markdown
1815 *
1816 * call-seq:
1817 * end(n) -> integer
1818 * end(name) -> integer
1819 *
1820 * Returns the offset (in characters) of the end of the specified match.
1821 *
1822 * With non-negative integer argument `n` given,
1823 * returns the character offset of the end of the `n`th match:
1824 *
1825 * ```ruby
1826 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1827 * match = '2026-12-25'.match(regexp)
1828 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1829 * match[0] # => "2026-12-25"
1830 * match.end(0) # => 10
1831 * match[3] # => "25"
1832 * match.end(3) # => 10
1833 * match.end(10) # Raises IndexError: index 10 out of matches.
1834 *
1835 * match = /(ん)(に)(ち)/.match('こんにちは')
1836 * # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
1837 * match[2] # => "に"
1838 * match.end(2) # => 3 # Character offset.
1839 * match.byteend(2) # => 9 # Byte offset.
1840 * ```
1841 *
1842 * With string or symbol argument `name` given, returns the offset of the end for the named match:
1843 *
1844 * ```ruby
1845 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1846 * match = '2026-12-25'.match(regexp)
1847 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1848 * match[:year] # => "2026"
1849 * match.end(:year) # => 4
1850 * match.end('month') # => 7
1851 * ```
1852 *
1853 * Related: MatchData#byteend.
1854 *
1855 */
1856
1857static VALUE
1858match_end(VALUE match, VALUE n)
1859{
1860 int i = match_backref_number(match, n);
1861
1862 match_check(match);
1863 backref_number_check(match, i);
1864
1865 if (RMATCH_BEG(match, i) < 0)
1866 return Qnil;
1867
1868 update_char_offset(match);
1869 return LEN2NUM(RMATCH(match)->char_offset[i].end);
1870}
1871
1872/*
1873 * :markup: markdown
1874 *
1875 * call-seq:
1876 * match(n) -> string or nil
1877 * match(name) -> string or nil
1878 *
1879 * Returns the matched substring corresponding to the given argument.
1880 *
1881 * With non-negative integer argument `n` given,
1882 * returns the matched substring for the `n`th match:
1883 *
1884 * ```ruby
1885 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1886 * match = '2026-12-25'.match(regexp)
1887 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1888 * match.match(0) # => "2026-12-25"
1889 * match.match(1) # => "2026"
1890 * match.match(2) # => "12"
1891 * match.match(3) # => "25"
1892 * match.match(4) # Raises IndexError: index 4 out of matches.
1893 * ```
1894 *
1895 * Except for `n == 0`, these same values are available
1896 * in [Regexp global variables][regexp global variables]:
1897 *
1898 * ```ruby
1899 * $0 # Returns the name of the current program.
1900 * $1 # => "2026"
1901 * $2 # => "12"
1902 * $3 # => "25"
1903 * $4 # => nil
1904 * ```
1905 *
1906 * Returns `nil` for an optional capture that had no match:
1907 *
1908 * ```ruby
1909 * match = /(\d+)(?:-(\d+))?/.match('123')
1910 * # => #<MatchData "123" 1:"123" 2:nil>
1911 * match.match(0) # => "123"
1912 * match.match(1) # => "123"
1913 * match.match(2) # => nil
1914 * ```
1915 *
1916 * With string or symbol argument `name` given,
1917 * returns the matched substring for the given name:
1918 *
1919 * ```ruby
1920 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1921 * match = '2026-12-25'.match(regexp)
1922 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1923 * match.match(:year) # => "2026"
1924 * match.match('day') # => "25"
1925 * match.match(:nosuch) # Raises IndexError: undefined group name reference: nosuch.
1926 * ```
1927 *
1928 * Returns `nil` for a named capture that had no match:
1929 *
1930 * ```ruby
1931 * match = /(?<year>\d{4})(?:-(?<month>\d{2}))?/.match('2026')
1932 * # => #<MatchData "2026" year:"2026" month:nil>
1933 * match.match(:year) # => "2026"
1934 * match.match(:month) # => nil
1935 * ```
1936 *
1937 * [regexp global variables]: rdoc-ref:Regexp@Global+Variables
1938 */
1939
1940static VALUE
1941match_nth(VALUE match, VALUE n)
1942{
1943 int i = match_backref_number(match, n);
1944
1945 backref_number_check(match, i);
1946
1947 rb_len_t start = RMATCH_BEG(match, i), end = RMATCH_END(match, i);
1948 if (start < 0)
1949 return Qnil;
1950
1951 return rb_str_subseq(RMATCH(match)->str, start, end - start);
1952}
1953
1954/*
1955 * :markup: markdown
1956 *
1957 * call-seq:
1958 * match_length(n) -> integer
1959 * match_length(name) -> integer
1960 *
1961 * Returns the length (in characters) of the matched substring
1962 * corresponding to the given argument.
1963 *
1964 * With non-negative integer argument `n` given,
1965 * returns the length of the matched substring
1966 * for the `n`th match:
1967 *
1968 * ```ruby
1969 * regexp = /(\d{4})-(\d{2})-(\d{2})/
1970 * match = '2026-12-25'.match(regexp)
1971 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
1972 * match.match_length(0) # => 10
1973 * match.match_length(3) # => 2
1974 * match.match_length(4) # Raises IndexError: index 4 out of matches.
1975 *
1976 * s = 'こんにちは' # Four 3-byte characters.
1977 * match = /(こん)(に)(ち)/.match(s)
1978 * # => #<MatchData "こんにち" 1:"こん" 2:"に" 3:"ち">
1979 * match.match_length(0) # => 4
1980 * match.match_length(1) # => 2
1981 * match.match_length(3) # => 1
1982 * match.match_length(4) # Raises IndexError: index 4 out of matches.
1983 * ```
1984 *
1985 *
1986 * With string or symbol argument `name` given,
1987 * returns the length of the matched substring
1988 * for the named match:
1989 *
1990 * ```ruby
1991 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
1992 * match = '2026-12-25'.match(regexp)
1993 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
1994 * match.match_length(:year) # => 4
1995 * match.match_length('day') # => 2
1996 * match.match_length(:nosuch) # Raises IndexError: undefined group name reference: nosuch.
1997 * ```
1998 *
1999 */
2000
2001static VALUE
2002match_nth_length(VALUE match, VALUE n)
2003{
2004 int i = match_backref_number(match, n);
2005
2006 match_check(match);
2007 backref_number_check(match, i);
2008
2009 if (RMATCH_BEG(match, i) < 0)
2010 return Qnil;
2011
2012 update_char_offset(match);
2013 const struct rmatch_offset *const ofs =
2014 &RMATCH(match)->char_offset[i];
2015 return LEN2NUM(ofs->end - ofs->beg);
2016}
2017
2018void
2020{
2021 FL_SET(match, MATCH_BUSY);
2022}
2023
2024void
2025rb_match_unbusy(VALUE match)
2026{
2027 FL_UNSET(match, MATCH_BUSY);
2028}
2029
2030int
2031rb_match_count(VALUE match)
2032{
2033 if (NIL_P(match)) return -1;
2034 return RMATCH_NREGS(match);
2035}
2036
2037static VALUE
2038match_alloc_or_reuse(VALUE existing, int num_regs)
2039{
2040 /* $~ can hold a Ractor::MovedObject: Ractor#send(move: true) hollows the
2041 * MatchData out in place and the husk keeps the old RMatch body, so its capa
2042 * still reads as reusable. Reusing it would write RMatch fields into a frozen
2043 * T_OBJECT, so check the type before trusting the body. */
2044 if (!NIL_P(existing) &&
2045 RB_TYPE_P(existing, T_MATCH) &&
2046 !FL_TEST(existing, MATCH_BUSY) &&
2047 RMATCH(existing)->capa >= num_regs * 2) {
2048 return existing;
2049 }
2050 return match_alloc_n(rb_cMatch, num_regs);
2051}
2052
2053static void
2054match_set_string(VALUE m, VALUE string, rb_len_t pos, rb_len_t len)
2055{
2056 struct RMatch *match = (struct RMatch *)m;
2057
2058 RB_OBJ_WRITE(match, &match->str, string);
2059 RB_OBJ_WRITE(match, &match->regexp, Qnil);
2060 OnigPosition beg = pos, end = pos + len;
2061 match_set_regs(m, 1, &beg, &end);
2062}
2063
2064VALUE
2065rb_backref_set_string(VALUE string, rb_len_t pos, rb_len_t len)
2066{
2067 VALUE match = match_alloc_or_reuse(rb_backref_get(), 1);
2068 match_set_string(match, string, pos, len);
2069 rb_backref_set(match);
2070 return match;
2071}
2072
2073/*
2074 * call-seq:
2075 * fixed_encoding? -> true or false
2076 *
2077 * Returns +false+ if +self+ is applicable to
2078 * a string with any ASCII-compatible encoding;
2079 * otherwise returns +true+:
2080 *
2081 * r = /a/ # => /a/
2082 * r.fixed_encoding? # => false
2083 * r.match?("\u{6666} a") # => true
2084 * r.match?("\xa1\xa2 a".force_encoding("euc-jp")) # => true
2085 * r.match?("abc".force_encoding("euc-jp")) # => true
2086 *
2087 * r = /a/u # => /a/
2088 * r.fixed_encoding? # => true
2089 * r.match?("\u{6666} a") # => true
2090 * r.match?("\xa1\xa2".force_encoding("euc-jp")) # Raises exception.
2091 * r.match?("abc".force_encoding("euc-jp")) # => true
2092 *
2093 * r = /\u{6666}/ # => /\u{6666}/
2094 * r.fixed_encoding? # => true
2095 * r.encoding # => #<Encoding:UTF-8>
2096 * r.match?("\u{6666} a") # => true
2097 * r.match?("\xa1\xa2".force_encoding("euc-jp")) # Raises exception.
2098 * r.match?("abc".force_encoding("euc-jp")) # => false
2099 *
2100 */
2101
2102static VALUE
2103rb_reg_fixed_encoding_p(VALUE re)
2104{
2105 return RBOOL(FL_TEST(re, KCODE_FIXED));
2106}
2107
2108static VALUE
2109rb_reg_preprocess(const char *p, const char *end, rb_encoding *enc,
2110 rb_encoding **fixed_enc, onig_errmsg_buffer err, int options);
2111
2112NORETURN(static void reg_enc_error(VALUE re, VALUE str));
2113
2114static void
2115reg_enc_error(VALUE re, VALUE str)
2116{
2117 rb_raise(rb_eEncCompatError,
2118 "incompatible encoding regexp match (%s regexp with %s string)",
2119 rb_enc_inspect_name(rb_enc_get(re)),
2120 rb_enc_inspect_name(rb_enc_get(str)));
2121}
2122
2123static rb_encoding*
2124rb_reg_prepare_enc(VALUE re, VALUE str, int warn)
2125{
2126 rb_encoding *enc = 0;
2127 int cr = rb_enc_str_coderange(str);
2128
2129 if (cr == ENC_CODERANGE_BROKEN) {
2130 rb_raise(rb_eArgError,
2131 "invalid byte sequence in %s",
2132 rb_enc_name(rb_enc_get(str)));
2133 }
2134
2135 rb_reg_check(re);
2136 enc = rb_enc_get(str);
2137 if (RREGEXP_PTR(re)->enc == enc) {
2138 }
2139 else if (cr == ENC_CODERANGE_7BIT &&
2140 RREGEXP_PTR(re)->enc == rb_usascii_encoding()) {
2141 enc = RREGEXP_PTR(re)->enc;
2142 }
2143 else if (!rb_enc_asciicompat(enc)) {
2144 reg_enc_error(re, str);
2145 }
2146 else if (rb_reg_fixed_encoding_p(re)) {
2147 if ((!rb_enc_asciicompat(RREGEXP_PTR(re)->enc) ||
2148 cr != ENC_CODERANGE_7BIT)) {
2149 reg_enc_error(re, str);
2150 }
2151 enc = RREGEXP_PTR(re)->enc;
2152 }
2153 else if (warn && (RBASIC(re)->flags & REG_ENCODING_NONE) &&
2154 enc != rb_ascii8bit_encoding() &&
2155 cr != ENC_CODERANGE_7BIT) {
2156 rb_warn("historical binary regexp match /.../n against %s string",
2157 rb_enc_name(enc));
2158 }
2159 return enc;
2160}
2161
2162static regex_t *
2163reg_find_encoding(struct rb_regexp_variant *variant, rb_encoding *enc)
2164{
2165 for (; variant; variant = variant->next) {
2166 if (variant->reg.enc == enc) return &variant->reg;
2167 }
2168 return NULL;
2169}
2170
2171static regex_t *
2172reg_prepare_re(VALUE re, VALUE str, bool caller_owned)
2173{
2174 int r;
2175 OnigErrorInfo einfo;
2176 VALUE unescaped;
2177 rb_encoding *fixed_enc = 0;
2178 rb_encoding *enc = rb_reg_prepare_enc(re, str, 1);
2179
2180 regex_t *reg = RREGEXP_PTR(re);
2181 if (reg->enc == enc) return reg;
2182
2183 struct rb_regexp_variant *head = RUBY_ATOMIC_PTR_LOAD(RREGEXP(re)->variants);
2184 regex_t *cached = reg_find_encoding(head, enc);
2185 if (cached && !caller_owned) return cached;
2186
2187 VALUE src_str = RREGEXP_SRC(re);
2188 const char *pattern = RSTRING_PTR(src_str);
2189
2190 onig_errmsg_buffer err = "";
2191 unescaped = rb_reg_preprocess(
2192 pattern, pattern + RSTRING_LEN(src_str), enc,
2193 &fixed_enc, err, reg->options);
2194
2195 if (NIL_P(unescaped)) {
2196 rb_raise(rb_eArgError, "regexp preprocess failed: %s", err);
2197 }
2198
2199 // inherit the timeout settings
2200 rb_hrtime_t timelimit = reg->timelimit;
2201
2202 const char *ptr;
2203 rb_len_t len;
2204 RSTRING_GETMEM(unescaped, ptr, len);
2205
2206 struct rb_regexp_variant *variant = ALLOC(struct rb_regexp_variant);
2207 r = onig_new_without_alloc(&variant->reg, (UChar *)ptr, (UChar *)(ptr + len),
2208 reg->options, enc, OnigDefaultSyntax, &einfo);
2209
2210 if (r) {
2211 onig_free_body(&variant->reg);
2212 SIZED_FREE(variant);
2213 onig_error_code_to_str((UChar*)err, r, &einfo);
2214 rb_reg_raise(err, re);
2215 }
2216
2217 reg = &variant->reg;
2218 reg->timelimit = timelimit;
2219 if (reg->num_mem != RREGEXP_PTR(re)->num_mem) {
2220 rb_bug("group count mismatch in the recompiled regexp: %d != %d", reg->num_mem, RREGEXP_PTR(re)->num_mem);
2221 }
2222
2223 if (caller_owned) {
2224 /* onig_free() releases with libc free(), so don't use ALLOC here. */
2225 reg = malloc(sizeof(regex_t));
2226 if (!reg) {
2227 onig_free_body(&variant->reg);
2228 SIZED_FREE(variant);
2229 rb_memerror();
2230 }
2231 *reg = variant->reg;
2232 SIZED_FREE(variant);
2233 RB_GC_GUARD(unescaped);
2234 return reg;
2235 }
2236
2237 /* Published variants are immutable and stay alive with re. Only the head
2238 * changes; a failed CAS may mean another Ractor compiled this encoding. */
2239 for (;;) {
2240 variant->next = head;
2241 struct rb_regexp_variant *previous = RUBY_ATOMIC_PTR_CAS(RREGEXP(re)->variants, head, variant);
2242 if (previous == head) break;
2243
2244 head = previous;
2245 cached = reg_find_encoding(head, enc);
2246 if (cached) {
2247 /* Discard our reg and use the cached version */
2248 onig_free_body(&variant->reg);
2249 SIZED_FREE(variant);
2250 reg = cached;
2251 break;
2252 }
2253 }
2254
2255 RB_GC_GUARD(unescaped);
2256 RB_GC_GUARD(src_str);
2257 RB_GC_GUARD(re);
2258 return reg;
2259}
2260
2261/* Callers of this public API free the result with onig_free() if it is not
2262 * RREGEXP_PTR(re), so return a copy and keep variants private. */
2263regex_t *
2265{
2266 return reg_prepare_re(re, str, true);
2267}
2268
2269OnigPosition
2271 OnigPosition (*match)(regex_t *reg, VALUE str, struct re_registers *regs, void *args),
2272 void *args, struct re_registers *regs)
2273{
2274 regex_t *reg = reg_prepare_re(re, str, false);
2275
2276 OnigPosition result = match(reg, str, regs, args);
2277
2278 RB_GC_GUARD(re);
2279
2280 if (result < 0) {
2281 switch (result) {
2282 case ONIG_MISMATCH:
2283 break;
2284 case ONIGERR_TIMEOUT:
2285 rb_raise(rb_eRegexpTimeoutError, "regexp match timeout");
2286 default: {
2287 onig_errmsg_buffer err = "";
2288 onig_error_code_to_str((UChar*)err, (int)result);
2289 rb_reg_raise(err, re);
2290 }
2291 }
2292 }
2293
2294 return result;
2295}
2296
2298rb_reg_adjust_startpos(VALUE re, VALUE str, rb_len_t pos, int reverse)
2299{
2300 rb_len_t range;
2301 rb_encoding *enc;
2302 UChar *p, *string;
2303
2304 enc = rb_reg_prepare_enc(re, str, 0);
2305
2306 if (reverse) {
2307 range = -pos;
2308 }
2309 else {
2310 range = RSTRING_LEN(str) - pos;
2311 }
2312
2313 if (pos > 0 && ONIGENC_MBC_MAXLEN(enc) != 1 && pos < RSTRING_LEN(str)) {
2314 string = (UChar*)RSTRING_PTR(str);
2315
2316 if (range > 0) {
2317 p = onigenc_get_right_adjust_char_head(enc, string, string + pos, string + RSTRING_LEN(str));
2318 }
2319 else {
2320 p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, string, string + pos, string + RSTRING_LEN(str));
2321 }
2322 return p - string;
2323 }
2324
2325 return pos;
2326}
2327
2329 rb_len_t pos;
2330 rb_len_t range;
2331};
2332
2333static OnigPosition
2334reg_onig_search(regex_t *reg, VALUE str, struct re_registers *regs, void *args_ptr)
2335{
2336 struct reg_onig_search_args *args = (struct reg_onig_search_args *)args_ptr;
2337 const char *ptr;
2338 rb_len_t len;
2339 RSTRING_GETMEM(str, ptr, len);
2340
2341 return onig_search(
2342 reg,
2343 (UChar *)ptr,
2344 (UChar *)(ptr + len),
2345 (UChar *)(ptr + args->pos),
2346 (UChar *)(ptr + args->range),
2347 regs,
2348 ONIG_OPTION_NONE);
2349}
2350
2351/* returns byte offset */
2352static rb_len_t
2353rb_reg_search_set_match(VALUE re, VALUE str, rb_len_t pos, int reverse, int set_backref_str, VALUE *set_match)
2354{
2355 rb_len_t len = RSTRING_LEN(str);
2356 if (pos > len || pos < 0) {
2358 return -1;
2359 }
2360
2361 struct reg_onig_search_args args = {
2362 .pos = pos,
2363 .range = reverse ? 0 : len,
2364 };
2365
2366 rb_reg_check(re);
2367
2368 /* Stack-backed regs sized to max(num_mem+1, ONIG_NREGION) so
2369 * onig_region_resize_clear takes its no-op branch. */
2370 int n = RREGEXP_PTR(re)->num_mem + 1;
2371 int cap = n < ONIG_NREGION ? ONIG_NREGION : n;
2372 VALUE regs_buf;
2373 OnigPosition *buf = ALLOCV_N(OnigPosition, regs_buf, (size_t)cap * 2);
2374 struct re_registers regs = {
2375 .allocated = cap,
2376 .num_regs = 0,
2377 .beg = buf,
2378 .end = buf + cap,
2379 };
2380
2381 OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, &regs);
2382
2383 if (result == ONIG_MISMATCH) {
2384 ALLOCV_END(regs_buf);
2386 return ONIG_MISMATCH;
2387 }
2388
2389 VALUE existing = (set_match && !NIL_P(*set_match)) ? *set_match : rb_backref_get();
2390 VALUE match = match_alloc_or_reuse(existing, regs.num_regs);
2391
2392 match_set_regs(match, regs.num_regs, regs.beg, regs.end);
2393 ALLOCV_END(regs_buf);
2394
2395 if (set_backref_str) {
2396 RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
2397 rb_obj_reveal(match, rb_cMatch);
2398 }
2399 else {
2400 /* Note that a MatchData object with RMATCH(match)->str == 0 is incomplete!
2401 * We need to hide the object from ObjectSpace.each_object.
2402 * https://bugs.ruby-lang.org/issues/19159
2403 */
2404 rb_obj_hide(match);
2405 }
2406
2407 RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
2408 rb_backref_set(match);
2409 if (set_match) *set_match = match;
2410
2411 return result;
2412}
2413
2415rb_reg_search0(VALUE re, VALUE str, rb_len_t pos, int reverse, int set_backref_str, VALUE *match)
2416{
2417 return rb_reg_search_set_match(re, str, pos, reverse, set_backref_str, match);
2418}
2419
2421rb_reg_search(VALUE re, VALUE str, rb_len_t pos, int reverse)
2422{
2423 return rb_reg_search_set_match(re, str, pos, reverse, 1, NULL);
2424}
2425
2426static OnigPosition
2427reg_onig_match(regex_t *reg, VALUE str, struct re_registers *regs, void *_)
2428{
2429 const char *ptr;
2430 rb_len_t len;
2431 RSTRING_GETMEM(str, ptr, len);
2432
2433 return onig_match(
2434 reg,
2435 (UChar *)ptr,
2436 (UChar *)(ptr + len),
2437 (UChar *)ptr,
2438 regs,
2439 ONIG_OPTION_NONE);
2440}
2441
2442bool
2443rb_reg_start_with_p(VALUE re, VALUE str)
2444{
2445 rb_reg_check(re);
2446
2447 int n = RREGEXP_PTR(re)->num_mem + 1;
2448 int cap = n < ONIG_NREGION ? ONIG_NREGION : n;
2449 VALUE regs_buf;
2450 OnigPosition *buf = ALLOCV_N(OnigPosition, regs_buf, (size_t)cap * 2);
2451 struct re_registers regs = {
2452 .allocated = cap,
2453 .num_regs = 0,
2454 .beg = buf,
2455 .end = buf + cap,
2456 };
2457
2458 if (rb_reg_onig_match(re, str, reg_onig_match, NULL, &regs) == ONIG_MISMATCH) {
2459 ALLOCV_END(regs_buf);
2461 return false;
2462 }
2463
2464 VALUE match = match_alloc_or_reuse(rb_backref_get(), regs.num_regs);
2465 match_set_regs(match, regs.num_regs, regs.beg, regs.end);
2466 ALLOCV_END(regs_buf);
2467
2468 RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
2469 RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
2470 rb_backref_set(match);
2471
2472 return true;
2473}
2474
2475VALUE
2477{
2478 if (NIL_P(match)) return Qnil;
2479 match_check(match);
2480 int num_regs = RMATCH_NREGS(match);
2481 if (nth >= num_regs) {
2482 return Qnil;
2483 }
2484 if (nth < 0) {
2485 nth += num_regs;
2486 if (nth <= 0) return Qnil;
2487 }
2488 return RBOOL(RMATCH_BEG(match, nth) != -1);
2489}
2490
2491VALUE
2493{
2494 VALUE str;
2495 rb_len_t start, end, len;
2496
2497 if (NIL_P(match)) return Qnil;
2498 match_check(match);
2499 int num_regs = RMATCH_NREGS(match);
2500 if (nth >= num_regs) {
2501 return Qnil;
2502 }
2503 if (nth < 0) {
2504 nth += num_regs;
2505 if (nth <= 0) return Qnil;
2506 }
2507 start = RMATCH_BEG(match, nth);
2508 if (start == -1) return Qnil;
2509 end = RMATCH_END(match, nth);
2510 len = end - start;
2511 str = rb_str_subseq(RMATCH(match)->str, start, len);
2512 return str;
2513}
2514
2515VALUE
2517{
2518 return rb_reg_nth_match(0, match);
2519}
2520
2521
2522/*
2523 * :markup: markdown
2524 *
2525 * call-seq:
2526 * pre_match -> string
2527 *
2528 * Returns the substring of the target string that precedes the matched substring;
2529 * equivalent to [Regexp global variable][regexp global variable] <tt>$`</tt>:
2530 *
2531 * ```ruby
2532 * match = /\d+/.match('foo 123 bar 456')
2533 * # => #<MatchData "123">
2534 * match.match(0) # => "123"
2535 * match.pre_match # => "foo "
2536 * ```
2537 *
2538 * [regexp global variable]: rdoc-ref:Regexp@Global+Variables
2539 */
2540
2541VALUE
2543{
2544 VALUE str;
2545
2546 if (NIL_P(match)) return Qnil;
2547 match_check(match);
2548 if (RMATCH_BEG(match, 0) == -1) return Qnil;
2549 str = rb_str_subseq(RMATCH(match)->str, 0, RMATCH_BEG(match, 0));
2550 return str;
2551}
2552
2553
2554/*
2555 * :markup: markdown
2556 *
2557 * call-seq:
2558 * post_match -> string
2559 *
2560 * Returns the substring of the target string that follows the matched substring;
2561 * equivalent to [Regexp global variable][regexp global variable] `$'`:
2562 *
2563 * ```ruby
2564 * match = /\d+/.match('foo 123 bar 456')
2565 * # => #<MatchData "123">
2566 * match.match(0) # => "123"
2567 * match.post_match # => " bar 456"
2568 * ```
2569 *
2570 * [regexp global variable]: rdoc-ref:Regexp@Global+Variables
2571 */
2572
2573VALUE
2575{
2576 VALUE str;
2577 rb_len_t pos;
2578
2579 if (NIL_P(match)) return Qnil;
2580 match_check(match);
2581 if (RMATCH_BEG(match, 0) == -1) return Qnil;
2582 str = RMATCH(match)->str;
2583 pos = RMATCH_END(match, 0);
2584 str = rb_str_subseq(str, pos, RSTRING_LEN(str) - pos);
2585 return str;
2586}
2587
2588static int
2589match_last_index(VALUE match)
2590{
2591 int i;
2592
2593 if (NIL_P(match)) return -1;
2594 match_check(match);
2595 if (RMATCH_BEG(match, 0) == -1) return -1;
2596
2597 for (i = RMATCH_NREGS(match) - 1; RMATCH_BEG(match, i) == -1 && i > 0; i--)
2598 ;
2599 return i;
2600}
2601
2602VALUE
2604{
2605 int i = match_last_index(match);
2606 if (i <= 0) return Qnil;
2607 rb_len_t start = RMATCH_BEG(match, i);
2608 return rb_str_subseq(RMATCH(match)->str, start, RMATCH_END(match, i) - start);
2609}
2610
2611VALUE
2612rb_reg_last_defined(VALUE match)
2613{
2614 int i = match_last_index(match);
2615 if (i < 0) return Qnil;
2616 return RBOOL(i);
2617}
2618
2619static VALUE
2620last_match_getter(ID _x, VALUE *_y)
2621{
2623}
2624
2625static VALUE
2626prematch_getter(ID _x, VALUE *_y)
2627{
2629}
2630
2631static VALUE
2632postmatch_getter(ID _x, VALUE *_y)
2633{
2635}
2636
2637static VALUE
2638last_paren_match_getter(ID _x, VALUE *_y)
2639{
2641}
2642
2643static VALUE
2644match_array(VALUE match, int start)
2645{
2646 VALUE ary;
2647 VALUE target;
2648 int i;
2649
2650 match_check(match);
2651 int num_regs = RMATCH_NREGS(match);
2652 ary = rb_ary_new2(num_regs);
2653 target = RMATCH(match)->str;
2654
2655 for (i = start; i < num_regs; i++) {
2656 rb_len_t beg = RMATCH_BEG(match, i);
2657 if (beg == -1) {
2658 rb_ary_push(ary, Qnil);
2659 }
2660 else {
2661 VALUE str = rb_str_subseq(target, beg, RMATCH_END(match, i) - beg);
2662 rb_ary_push(ary, str);
2663 }
2664 }
2665 return ary;
2666}
2667
2668
2669/*
2670 * :markup: markdown
2671 *
2672 * call-seq:
2673 * to_a -> array
2674 *
2675 * Returns the array of matched substrings:
2676 *
2677 * ```ruby
2678 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
2679 * match = '2026-12-25'.match(regexp)
2680 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
2681 * match.to_a # => ["2026-12-25", "2026", "12", "25"]
2682 * ```
2683 *
2684 */
2685
2686static VALUE
2687match_to_a(VALUE match)
2688{
2689 return match_array(match, 0);
2690}
2691
2692
2693/*
2694 * :markup: markdown
2695 *
2696 * call-seq:
2697 * captures -> array
2698 *
2699 * Returns an array of the captured substrings,
2700 * including all except the entire matched substring:
2701 *
2702 * ```ruby
2703 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
2704 * match = '2026-12-25'.match(regexp)
2705 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
2706 * match.captures # => ["2026", "12", "25"]
2707 * match[1..] # => ["2026", "12", "25"] # Included in array.
2708 * match[0] # => "2026-12-25" # Not included in array.
2709 * ```
2710 *
2711 * Related: MatchData.to_a.
2712 *
2713 */
2714static VALUE
2715match_captures(VALUE match)
2716{
2717 return match_array(match, 1);
2718}
2719
2720static int
2721name_to_backref_number(const struct re_registers *regs, VALUE regexp, const char* name, const char* name_end)
2722{
2723 if (NIL_P(regexp)) return -1;
2724 return onig_name_to_backref_number(RREGEXP_PTR(regexp),
2725 (const unsigned char *)name, (const unsigned char *)name_end, regs);
2726}
2727
2728#define NAME_TO_NUMBER(regs, re, name, name_ptr, name_end) \
2729 (NIL_P(re) ? 0 : \
2730 !rb_enc_compatible(RREGEXP_SRC(re), (name)) ? 0 : \
2731 name_to_backref_number((regs), (re), (name_ptr), (name_end)))
2732
2733static int
2734match_name_to_backref_number(VALUE match, VALUE name)
2735{
2736 VALUE regexp = RMATCH(match)->regexp;
2737 if (NIL_P(regexp)) return -1;
2738
2739 int *nums;
2740 int n = onig_name_to_group_numbers(RREGEXP_PTR(regexp),
2741 (const unsigned char *)RSTRING_PTR(name),
2742 (const unsigned char *)RSTRING_END(name), &nums);
2743 if (n < 0) return n;
2744 if (n == 0) return ONIGERR_PARSER_BUG;
2745 if (n == 1) return nums[0];
2746 for (int i = n - 1; i >= 0; i--) {
2747 if (RMATCH_BEG(match, nums[i]) != ONIG_REGION_NOTPOS)
2748 return nums[i];
2749 }
2750 return nums[n - 1];
2751}
2752
2753static int
2754namev_to_backref_number(VALUE match, VALUE name)
2755{
2756 int num;
2757
2758 if (SYMBOL_P(name)) {
2759 name = rb_sym2str(name);
2760 }
2761 else if (!RB_TYPE_P(name, T_STRING)) {
2762 return -1;
2763 }
2764
2765 VALUE re = RMATCH(match)->regexp;
2766 if (NIL_P(re) || !rb_enc_compatible(RREGEXP_SRC(re), name)) {
2767 num = 0;
2768 }
2769 else {
2770 num = match_name_to_backref_number(match, name);
2771 }
2772 if (num < 1) {
2773 name_to_backref_error(name);
2774 }
2775 return num;
2776}
2777
2778static VALUE
2779match_ary_subseq(VALUE match, rb_len_t beg, rb_len_t len, VALUE result)
2780{
2781 rb_len_t olen = RMATCH_NREGS(match);
2782 rb_len_t j, end = olen < beg+len ? olen : beg+len;
2783 if (NIL_P(result)) result = rb_ary_new_capa(len);
2784 if (len == 0) return result;
2785
2786 for (j = beg; j < end; j++) {
2787 rb_ary_push(result, rb_reg_nth_match((int)j, match));
2788 }
2789 if (beg + len > j) {
2790 rb_ary_resize(result, RARRAY_LEN(result) + (beg + len) - j);
2791 }
2792 return result;
2793}
2794
2795static VALUE
2796match_ary_aref(VALUE match, VALUE idx, VALUE result)
2797{
2798 rb_len_t beg, len;
2799 int num_regs = RMATCH_NREGS(match);
2800
2801 /* check if idx is Range */
2802 switch (rb_range_beg_len(idx, &beg, &len, (rb_len_t)num_regs, !NIL_P(result))) {
2803 case Qfalse:
2804 if (NIL_P(result)) return rb_reg_nth_match(NUM2INT(idx), match);
2805 rb_ary_push(result, rb_reg_nth_match(NUM2INT(idx), match));
2806 return result;
2807 case Qnil:
2808 return Qnil;
2809 default:
2810 return match_ary_subseq(match, beg, len, result);
2811 }
2812}
2813
2814/*
2815 * :markup: markdown
2816 *
2817 * call-seq:
2818 * self[n] -> string or nil
2819 * self[n, size] -> string or array
2820 * self[name] -> string or nil
2821 * self[range] -> array or nil
2822 *
2823 * With only integer argument `n` given,
2824 * returns the matched substring at offset `n`:
2825 *
2826 * ```ruby
2827 * regexp = /(\d{4})-(\d{2})-(\d{2})/
2828 * match = '2026-12-25'.match(regexp)
2829 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
2830 * match[0] # => "2026-12-25" # Entire matched string.
2831 * match[1] # => "2026" # First matched substring.
2832 * match[2] # => "12" # Second matched substring.
2833 * match[3] # => "25" # Third matched substring.
2834 * match[4] # => nil # No more matches.
2835 * match[-1] # => "25" # For negative offset, counts backwards.
2836 * ```
2837 *
2838 * With integer arguments `n` and `size` given,
2839 * returns `size` matched substrings beginning at offset `n`:
2840 *
2841 * ```ruby
2842 * regexp = /(\d{4})-(\d{2})-(\d{2})/
2843 * match = '2026-12-25'.match(regexp)
2844 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
2845 * match[0, 1] # => ["2026-12-25"]
2846 * match[0, 4] # => ["2026-12-25", "2026", "12", "25"]
2847 * match[0, 10] # => ["2026-12-25", "2026", "12", "25"]
2848 * match[-3, 2] # => ["2026", "12"]
2849 * match[0, 0] # => []
2850 * ```
2851 *
2852 * With string or symbol argument `name` given,
2853 * returns the named matched substring:
2854 *
2855 * ```ruby
2856 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
2857 * match = regexp.match('2026-10-27')
2858 * # => #<MatchData "2026-10-27" year:"2026" month:"10" day:"27">
2859 * match[:year] # => "2026"
2860 * match['day'] # => "27"
2861 * match[:nosuch] # Raises IndexError : undefined group name reference: nosuch.
2862 * ```
2863 *
2864 * If multiple captures have the same name, returns matched substring for the last one.
2865 *
2866 * With [bounded range][bounded range] argument `range` given,
2867 * returns an array of matched substrings:
2868 *
2869 * ```
2870 * regexp = /(\d{4})-(\d{2})-(\d{2})/
2871 * match = '2026-12-25'.match(regexp)
2872 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
2873 * match[0..2] # => ["2026-12-25", "2026", "12"]
2874 * match[0..10] # => ["2026-12-25", "2026", "12", "25"]
2875 * match[0..-3] # => ["2026-12-25", "2026"]
2876 * match[-3..2] # => ["2026", "12"]
2877 * ```
2878 *
2879 * With [beginless range][beginless range] argument `range` given,
2880 * returns an array of matched substrings:
2881 *
2882 * ```ruby
2883 * match[..0] # => ["2026-12-25"]
2884 * match[..1] # => ["2026-12-25", "2026"]
2885 * match[..10] # => ["2026-12-25", "2026", "12", "25"]
2886 * ```
2887 *
2888 * With [endless range][endless range] argument `range` given,
2889 * returns an array of matched substrings:
2890 *
2891 * ```ruby
2892 * match[0..] # => ["2026-12-25", "2026", "12", "25"]
2893 * match[2..] # => ["12", "25"]
2894 * match[10..] # => nil
2895 * ```
2896 *
2897 * With [unbounded range][unbounded range] argument `range` given,
2898 * returns an array of all matched substrings:
2899 *
2900 * ```ruby
2901 * match[nil..nil] # => ["2026-12-25", "2026", "12", "25"]
2902 * ```
2903 *
2904 * [bounded range]: rdoc-ref:Range@Bounded+Ranges
2905 * [beginless range]: rdoc-ref:Range@Beginless+Ranges
2906 * [endless range]: rdoc-ref:Range@Endless+Ranges
2907 * [unbounded range]: rdoc-ref:Range@Unbounded+Ranges
2908 *
2909 */
2910
2911static VALUE
2912match_aref(int argc, VALUE *argv, VALUE match)
2913{
2914 VALUE idx, length;
2915
2916 match_check(match);
2917 rb_scan_args(argc, argv, "11", &idx, &length);
2918
2919 if (NIL_P(length)) {
2920 if (FIXNUM_P(idx)) {
2921 return rb_reg_nth_match(FIX2INT(idx), match);
2922 }
2923 else {
2924 int num = namev_to_backref_number(match, idx);
2925 if (num >= 0) {
2926 return rb_reg_nth_match(num, match);
2927 }
2928 else {
2929 return match_ary_aref(match, idx, Qnil);
2930 }
2931 }
2932 }
2933 else {
2934 rb_len_t beg = NUM2LEN(idx);
2935 rb_len_t len = NUM2LEN(length);
2936 rb_len_t num_regs = RMATCH_NREGS(match);
2937 if (len < 0) {
2938 return Qnil;
2939 }
2940 if (beg < 0) {
2941 beg += num_regs;
2942 if (beg < 0) return Qnil;
2943 }
2944 else if (beg > num_regs) {
2945 return Qnil;
2946 }
2947 if (beg+len > num_regs) {
2948 len = num_regs - beg;
2949 }
2950 return match_ary_subseq(match, beg, len, Qnil);
2951 }
2952}
2953
2954/*
2955 * :markup: markdown
2956 *
2957 * call-seq:
2958 * values_at(*indexes) -> array
2959 *
2960 * Returns an array of matched substrings as specified by the given `indexes`,
2961 * which may be any mixture of integers, names, and ranges.
2962 *
2963 * For each integer index `n`,
2964 * includes the `n`th matched substring:
2965 *
2966 * ```ruby
2967 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
2968 * match = '2026-12-25'.match(regexp)
2969 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
2970 * match.values_at(3, 1, 2, 0) # => ["25", "2026", "12", "2026-12-25"]
2971 * ```
2972 *
2973 * For negative `n`, counts backwards in the array of matched substrings:
2974 *
2975 * ```ruby
2976 * match.values_at(3, -1) # => ["25", "25"]
2977 * ```
2978 *
2979 * For `n` out of range, returns `nil`:
2980 *
2981 * ```ruby
2982 * match.values_at(4, -4) # => [nil, nil]
2983 * ```
2984 *
2985 * For each string or symbol index `name`,
2986 * includes the matched substring for that `name`:
2987 *
2988 * ```ruby
2989 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
2990 * match = '2026-12-25'.match(regexp)
2991 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
2992 * match.values_at(:day, 'year') # => ["25", "2026"]
2993 * match.values_at(:nosuch) # Raises IndexError: undefined group name reference: nosuch.
2994 * ```
2995 *
2996 * For a Range index `range`,
2997 * returns the matched substrings for the indexes covered by that `range`:
2998 *
2999 * ```ruby
3000 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
3001 * match = '2026-12-25'.match(regexp)
3002 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
3003 * match.values_at(1..2) # => ["2026", "12"]
3004 * match.values_at(1...3) # => ["2026", "12"]
3005 * ```
3006 *
3007 * For positive range value out-of-range, fills with `nil`:
3008 *
3009 * ```ruby
3010 * match.values_at(1..5) # => ["2026", "12", "25", nil, nil]
3011 * ```
3012 *
3013 * For negative range value, counts backwards in the array of matched substrings:
3014 *
3015 * ```ruby
3016 * match.values_at(-3..-1) # => ["2026", "12", "25"]
3017 * match.values_at(-5..-1) # Raises RangeError: -5..-1 out of range.
3018 * ```
3019 *
3020 * Mixed-type indexes:
3021 *
3022 * ```ruby
3023 * match.values_at(:year, 1, :month, 2, :day, 3, 0..3)
3024 * # => ["2026", "2026", "12", "12", "25", "25", "2026-12-25", "2026", "12", "25"]
3025 * ```
3026 *
3027 */
3028
3029static VALUE
3030match_values_at(int argc, VALUE *argv, VALUE match)
3031{
3032 VALUE result;
3033 int i;
3034
3035 match_check(match);
3036 result = rb_ary_new2(argc);
3037
3038 for (i=0; i<argc; i++) {
3039 if (FIXNUM_P(argv[i])) {
3040 rb_ary_push(result, rb_reg_nth_match(FIX2INT(argv[i]), match));
3041 }
3042 else {
3043 int num = namev_to_backref_number(match, argv[i]);
3044 if (num >= 0) {
3045 rb_ary_push(result, rb_reg_nth_match(num, match));
3046 }
3047 else {
3048 match_ary_aref(match, argv[i], result);
3049 }
3050 }
3051 }
3052 return result;
3053}
3054
3055
3056/*
3057 * :markup: markdown
3058 *
3059 * call-seq:
3060 * to_s -> string
3061 *
3062 * Returns the matched substring;
3063 * equivalent to #match(0):
3064 *
3065 * ```ruby
3066 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
3067 * match = '2026-12-25'.match(regexp)
3068 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
3069 * match.to_s # => "2026-12-25"
3070 * ```
3071 *
3072 */
3073
3074static VALUE
3075match_to_s(VALUE match)
3076{
3077 VALUE str = rb_reg_last_match(match_check(match));
3078
3079 if (NIL_P(str)) str = rb_str_new(0,0);
3080 return str;
3081}
3082
3084 VALUE hash;
3085 VALUE match;
3086 int symbolize;
3087};
3088
3089static int
3090match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
3091 int back_num, int *back_refs, OnigRegex regex, void *arg)
3092{
3093 struct named_captures_data *data = arg;
3094 VALUE hash = data->hash;
3095 VALUE match = data->match;
3096
3097 VALUE key = rb_enc_str_new((const char *)name, name_end-name, regex->enc);
3098
3099 if (data->symbolize) {
3100 key = rb_str_intern(key);
3101 }
3102
3103 VALUE value;
3104
3105 int i;
3106 int found = 0;
3107
3108 for (i = 0; i < back_num; i++) {
3109 value = rb_reg_nth_match(back_refs[i], match);
3110 if (RTEST(value)) {
3111 rb_hash_aset(hash, key, value);
3112 found = 1;
3113 }
3114 }
3115
3116 if (found == 0) {
3117 rb_hash_aset(hash, key, Qnil);
3118 }
3119
3120 return 0;
3121}
3122
3123/*
3124 * :markup: markdown
3125 *
3126 * call-seq:
3127 * named_captures(symbolize_names: false) -> hash
3128 *
3129 * Returns a hash of capture names and values:
3130 *
3131 * ```ruby
3132 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
3133 * match = '2026-12-25'.match(regexp)
3134 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
3135 * match.named_captures # => {"year" => "2026", "month" => "12", "day" => "25"}
3136 * ```
3137 *
3138 * With keyword argument `symbolize_names` given as `true`,
3139 * returns hash keys as symbols:
3140 *
3141 * ```ruby
3142 * match.named_captures(symbolize_names: true)
3143 * # => {year: "2026", month: "12", day: "25"}
3144 * ```
3145 *
3146 * Returns a `nil` hash value for a name that captured nothing:
3147 *
3148 * ```ruby
3149 * regexp = /(?<year>\d{4})-(?<month>\d{2})?/
3150 * # => /(?<year>\d{4})-(?<month>\d{2})?/
3151 * match = '2026-'.match(regexp)
3152 * # => #<MatchData "2026-" year:"2026" month:nil>
3153 * match.named_captures # => {"year" => "2026", "month" => nil}
3154 * ```
3155 *
3156 */
3157
3158static VALUE
3159match_named_captures(int argc, VALUE *argv, VALUE match)
3160{
3161 VALUE hash;
3162
3163 match_check(match);
3164 if (NIL_P(RMATCH(match)->regexp))
3165 return rb_hash_new();
3166
3167 VALUE opt;
3168 int symbolize_names = 0;
3169
3170 rb_scan_args(argc, argv, "0:", &opt);
3171
3172 if (!NIL_P(opt)) {
3173 static ID keyword_ids[1];
3174
3175 VALUE symbolize_names_val;
3176
3177 if (!keyword_ids[0]) {
3178 keyword_ids[0] = rb_intern_const("symbolize_names");
3179 }
3180 rb_get_kwargs(opt, keyword_ids, 0, 1, &symbolize_names_val);
3181 if (!UNDEF_P(symbolize_names_val) && RTEST(symbolize_names_val)) {
3182 symbolize_names = 1;
3183 }
3184 }
3185
3186 hash = rb_hash_new();
3187 struct named_captures_data data = { hash, match, symbolize_names };
3188
3189 onig_foreach_name(RREGEXP_PTR(RMATCH(match)->regexp), match_named_captures_iter, &data);
3190
3191 return hash;
3192}
3193
3194/*
3195 * :markup: markdown
3196 *
3197 * call-seq:
3198 * deconstruct_keys(object) -> hash
3199 *
3200 * With an array of symbol capture names given,
3201 * returns a hash of the names and values for the given names:
3202 *
3203 * ```ruby
3204 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
3205 * match = '2026-12-25'.match(regexp)
3206 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
3207 * match.deconstruct_keys([:day, :month]) # => {day: "25", month: "12"}
3208 * match.deconstruct_keys(['foo']) # Raises TypeError: wrong argument type String (expected Symbol).
3209 * ```
3210 *
3211 * Ignores symbols that are not capture names:
3212 *
3213 * ```ruby
3214 * match.deconstruct_keys([:foo]) # => {}
3215 * ```
3216 *
3217 * With `nil` given,
3218 * returns a hash of all capture names and values:
3219 *
3220 * ```ruby
3221 * match.deconstruct_keys(nil) # => {year: "2026", month: "12", day: "25"}
3222 * ```
3223 *
3224 * Returns an empty hash if no named captures were defined:
3225 *
3226 * ```ruby
3227 * regexp = /(\d{4})-(\d{2})-(\d{2})/
3228 * match = '2026-12-25'.match(regexp)
3229 * # => #<MatchData "2026-12-25" 1:"2026" 2:"12" 3:"25">
3230 * match.deconstruct_keys(nil) # => {}
3231 * ```
3232 *
3233 */
3234static VALUE
3235match_deconstruct_keys(VALUE match, VALUE keys)
3236{
3237 VALUE h;
3238 rb_len_t i;
3239
3240 match_check(match);
3241
3242 if (NIL_P(RMATCH(match)->regexp)) {
3243 return rb_hash_new();
3244 }
3245
3246 if (NIL_P(keys)) {
3247 h = rb_hash_new_capa(onig_number_of_names(RREGEXP_PTR(RMATCH(match)->regexp)));
3248
3249 struct named_captures_data data = { h, match, 1 };
3250
3251 onig_foreach_name(RREGEXP_PTR(RMATCH(match)->regexp), match_named_captures_iter, &data);
3252
3253 return h;
3254 }
3255
3256 Check_Type(keys, T_ARRAY);
3257
3258 if (onig_number_of_names(RREGEXP_PTR(RMATCH(match)->regexp)) < RARRAY_LEN(keys)) {
3259 return rb_hash_new();
3260 }
3261
3262 h = rb_hash_new_capa(RARRAY_LEN(keys));
3263
3264 for (i=0; i<RARRAY_LEN(keys); i++) {
3265 VALUE key = RARRAY_AREF(keys, i);
3266 VALUE name;
3267
3268 Check_Type(key, T_SYMBOL);
3269
3270 name = rb_sym2str(key);
3271
3272 int num = match_name_to_backref_number(match, name);
3273
3274 if (num >= 0) {
3275 rb_hash_aset(h, key, rb_reg_nth_match(num, match));
3276 }
3277 else {
3278 return h;
3279 }
3280 }
3281
3282 return h;
3283}
3284
3285/*
3286 * :markup: markdown
3287 *
3288 * call-seq:
3289 * string -> string
3290 *
3291 * Returns the target string if it was frozen;
3292 * otherwise, returns a frozen copy of the target string:
3293 *
3294 * ```ruby
3295 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
3296 * match = '2026-12-25'.match(regexp)
3297 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
3298 * match.string # => "2026-12-25"
3299 * ```
3300 *
3301 */
3302
3303static VALUE
3304match_string(VALUE match)
3305{
3306 match_check(match);
3307 return RMATCH(match)->str; /* str is frozen */
3308}
3309
3311 const UChar *name;
3312 rb_len_t len;
3313};
3314
3315static int
3316match_inspect_name_iter(const OnigUChar *name, const OnigUChar *name_end,
3317 int back_num, int *back_refs, OnigRegex regex, void *arg0)
3318{
3319 struct backref_name_tag *arg = (struct backref_name_tag *)arg0;
3320 int i;
3321
3322 for (i = 0; i < back_num; i++) {
3323 arg[back_refs[i]].name = name;
3324 arg[back_refs[i]].len = name_end - name;
3325 }
3326 return 0;
3327}
3328
3329/*
3330 * :markup: markdown
3331 *
3332 * call-seq:
3333 * inspect -> string
3334 *
3335 * Returns a string representation of `self`:
3336 *
3337 * ```ruby
3338 * regexp = /(\d{4})-(\d{2})-(\d{2})/
3339 * match = '2026-12-25'.match(regexp)
3340 * match.inspect # => "#<MatchData \"2026-12-25\" 1:\"2026\" 2:\"12\" 3:\"25\">"
3341 *
3342 * match = /(ん)(に)(ち)/.match('こんにちは')
3343 * match.inspect # => "#<MatchData \"んにち\" 1:\"ん\" 2:\"に\" 3:\"ち\">"
3344 *
3345 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
3346 * match = '2026-12-25'.match(regexp)
3347 * match.inspect # => "#<MatchData \"2026-12-25\" year:\"2026\" month:\"12\" day:\"25\">"
3348 * ```
3349 *
3350 * Related: MatchData#to_s.
3351 */
3352
3353static VALUE
3354match_inspect(VALUE match)
3355{
3356 VALUE cname = rb_class_path(rb_obj_class(match));
3357 VALUE str;
3358 int i;
3359 int num_regs = RMATCH_NREGS(match);
3360 struct backref_name_tag *names;
3361 VALUE names_obj = Qnil;
3362 VALUE regexp = RMATCH(match)->regexp;
3363
3364 if (regexp == 0) {
3365 return rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)match);
3366 }
3367 else if (NIL_P(regexp)) {
3368 return rb_sprintf("#<%"PRIsVALUE": %"PRIsVALUE">",
3369 cname, rb_reg_nth_match(0, match));
3370 }
3371
3372 names = RB_ALLOCV_N(struct backref_name_tag, names_obj, num_regs);
3373 MEMZERO(names, struct backref_name_tag, num_regs);
3374
3375 onig_foreach_name(RREGEXP_PTR(regexp),
3376 match_inspect_name_iter, names);
3377
3378 str = rb_str_buf_new2("#<");
3379 rb_str_append(str, cname);
3380
3381 for (i = 0; i < num_regs; i++) {
3382 VALUE v;
3383 rb_str_buf_cat2(str, " ");
3384 if (0 < i) {
3385 if (names[i].name)
3386 rb_str_buf_cat(str, (const char *)names[i].name, names[i].len);
3387 else {
3388 rb_str_catf(str, "%d", i);
3389 }
3390 rb_str_buf_cat2(str, ":");
3391 }
3392 v = rb_reg_nth_match(i, match);
3393 if (NIL_P(v))
3394 rb_str_buf_cat2(str, "nil");
3395 else
3397 }
3398 rb_str_buf_cat2(str, ">");
3399
3400 RB_ALLOCV_END(names_obj);
3401 return str;
3402}
3403
3405
3406static int
3407read_escaped_byte(const char **pp, const char *end, onig_errmsg_buffer err)
3408{
3409 const char *p = *pp;
3410 int code;
3411 int meta_prefix = 0, ctrl_prefix = 0;
3412 size_t len;
3413
3414 if (p == end || *p++ != '\\') {
3415 errcpy(err, "too short escaped multibyte character");
3416 return -1;
3417 }
3418
3419again:
3420 if (p == end) {
3421 errcpy(err, "too short escape sequence");
3422 return -1;
3423 }
3424 switch (*p++) {
3425 case '\\': code = '\\'; break;
3426 case 'n': code = '\n'; break;
3427 case 't': code = '\t'; break;
3428 case 'r': code = '\r'; break;
3429 case 'f': code = '\f'; break;
3430 case 'v': code = '\013'; break;
3431 case 'a': code = '\007'; break;
3432 case 'e': code = '\033'; break;
3433
3434 /* \OOO */
3435 case '0': case '1': case '2': case '3':
3436 case '4': case '5': case '6': case '7':
3437 p--;
3438 code = scan_oct(p, end < p+3 ? end-p : 3, &len);
3439 p += len;
3440 break;
3441
3442 case 'x': /* \xHH */
3443 code = scan_hex(p, end < p+2 ? end-p : 2, &len);
3444 if (len < 1) {
3445 errcpy(err, "invalid hex escape");
3446 return -1;
3447 }
3448 p += len;
3449 break;
3450
3451 case 'M': /* \M-X, \M-\C-X, \M-\cX */
3452 if (meta_prefix) {
3453 errcpy(err, "duplicate meta escape");
3454 return -1;
3455 }
3456 meta_prefix = 1;
3457 if (p+1 < end && *p++ == '-' && (*p & 0x80) == 0) {
3458 if (*p == '\\') {
3459 p++;
3460 goto again;
3461 }
3462 else {
3463 code = *p++;
3464 break;
3465 }
3466 }
3467 errcpy(err, "too short meta escape");
3468 return -1;
3469
3470 case 'C': /* \C-X, \C-\M-X */
3471 if (p == end || *p++ != '-') {
3472 errcpy(err, "too short control escape");
3473 return -1;
3474 }
3475 case 'c': /* \cX, \c\M-X */
3476 if (ctrl_prefix) {
3477 errcpy(err, "duplicate control escape");
3478 return -1;
3479 }
3480 ctrl_prefix = 1;
3481 if (p < end && (*p & 0x80) == 0) {
3482 if (*p == '\\') {
3483 p++;
3484 goto again;
3485 }
3486 else {
3487 code = *p++;
3488 break;
3489 }
3490 }
3491 errcpy(err, "too short control escape");
3492 return -1;
3493
3494 default:
3495 errcpy(err, "unexpected escape sequence");
3496 return -1;
3497 }
3498 if (code < 0 || 0xff < code) {
3499 errcpy(err, "invalid escape code");
3500 return -1;
3501 }
3502
3503 if (ctrl_prefix)
3504 code &= 0x1f;
3505 if (meta_prefix)
3506 code |= 0x80;
3507
3508 *pp = p;
3509 return code;
3510}
3511
3512static int
3513unescape_escaped_nonascii(const char **pp, const char *end, rb_encoding *enc,
3514 VALUE buf, rb_encoding **encp, onig_errmsg_buffer err)
3515{
3516 const char *p = *pp;
3517 int chmaxlen = rb_enc_mbmaxlen(enc);
3518 unsigned char *area = ALLOCA_N(unsigned char, chmaxlen);
3519 char *chbuf = (char *)area;
3520 int chlen = 0;
3521 int byte;
3522 int l;
3523
3524 memset(chbuf, 0, chmaxlen);
3525
3526 byte = read_escaped_byte(&p, end, err);
3527 if (byte == -1) {
3528 return -1;
3529 }
3530
3531 area[chlen++] = byte;
3532 while (chlen < chmaxlen &&
3533 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(chbuf, chbuf+chlen, enc))) {
3534 byte = read_escaped_byte(&p, end, err);
3535 if (byte == -1) {
3536 return -1;
3537 }
3538 area[chlen++] = byte;
3539 }
3540
3541 l = rb_enc_precise_mbclen(chbuf, chbuf+chlen, enc);
3542 if (MBCLEN_INVALID_P(l)) {
3543 errcpy(err, "invalid multibyte escape");
3544 return -1;
3545 }
3546 if (1 < chlen || (area[0] & 0x80)) {
3547 rb_str_buf_cat(buf, chbuf, chlen);
3548
3549 if (*encp == 0)
3550 *encp = enc;
3551 else if (*encp != enc) {
3552 errcpy(err, "escaped non ASCII character in UTF-8 regexp");
3553 return -1;
3554 }
3555 }
3556 else {
3557 char escbuf[5];
3558 snprintf(escbuf, sizeof(escbuf), "\\x%02X", area[0]&0xff);
3559 rb_str_buf_cat(buf, escbuf, 4);
3560 }
3561 *pp = p;
3562 return 0;
3563}
3564
3565static int
3566check_unicode_range(unsigned long code, onig_errmsg_buffer err)
3567{
3568 if ((0xd800 <= code && code <= 0xdfff) || /* Surrogates */
3569 0x10ffff < code) {
3570 errcpy(err, "invalid Unicode range");
3571 return -1;
3572 }
3573 return 0;
3574}
3575
3576static int
3577append_utf8(unsigned long uv,
3578 VALUE buf, rb_encoding **encp, onig_errmsg_buffer err)
3579{
3580 if (check_unicode_range(uv, err) != 0)
3581 return -1;
3582 if (uv < 0x80) {
3583 char escbuf[5];
3584 snprintf(escbuf, sizeof(escbuf), "\\x%02X", (int)uv);
3585 rb_str_buf_cat(buf, escbuf, 4);
3586 }
3587 else {
3588 int len;
3589 char utf8buf[6];
3590 len = rb_uv_to_utf8(utf8buf, uv);
3591 rb_str_buf_cat(buf, utf8buf, len);
3592
3593 if (*encp == 0)
3594 *encp = rb_utf8_encoding();
3595 else if (*encp != rb_utf8_encoding()) {
3596 errcpy(err, "UTF-8 character in non UTF-8 regexp");
3597 return -1;
3598 }
3599 }
3600 return 0;
3601}
3602
3603static int
3604unescape_unicode_list(const char **pp, const char *end,
3605 VALUE buf, rb_encoding **encp, onig_errmsg_buffer err)
3606{
3607 const char *p = *pp;
3608 int has_unicode = 0;
3609 unsigned long code;
3610 size_t len;
3611
3612 while (p < end && ISSPACE(*p)) p++;
3613
3614 while (1) {
3615 code = ruby_scan_hex(p, end-p, &len);
3616 if (len == 0)
3617 break;
3618 if (6 < len) { /* max 10FFFF */
3619 errcpy(err, "invalid Unicode range");
3620 return -1;
3621 }
3622 p += len;
3623 if (append_utf8(code, buf, encp, err) != 0)
3624 return -1;
3625 has_unicode = 1;
3626
3627 while (p < end && ISSPACE(*p)) p++;
3628 }
3629
3630 if (has_unicode == 0) {
3631 errcpy(err, "invalid Unicode list");
3632 return -1;
3633 }
3634
3635 *pp = p;
3636
3637 return 0;
3638}
3639
3640static int
3641unescape_unicode_bmp(const char **pp, const char *end,
3642 VALUE buf, rb_encoding **encp, onig_errmsg_buffer err)
3643{
3644 const char *p = *pp;
3645 size_t len;
3646 unsigned long code;
3647
3648 if (end < p+4) {
3649 errcpy(err, "invalid Unicode escape");
3650 return -1;
3651 }
3652 code = ruby_scan_hex(p, 4, &len);
3653 if (len != 4) {
3654 errcpy(err, "invalid Unicode escape");
3655 return -1;
3656 }
3657 if (append_utf8(code, buf, encp, err) != 0)
3658 return -1;
3659 *pp = p + 4;
3660 return 0;
3661}
3662
3663static int
3664unescape_nonascii0(const char **pp, const char *end, rb_encoding *enc,
3665 VALUE buf, rb_encoding **encp, int *has_property,
3666 onig_errmsg_buffer err, int options, int recurse)
3667{
3668 const char *p = *pp;
3669 unsigned char c;
3670 char smallbuf[2];
3671 int in_char_class = 0;
3672 int parens = 1; /* ignored unless recurse is true */
3673 int extended_mode = options & ONIG_OPTION_EXTEND;
3674
3675begin_scan:
3676 while (p < end) {
3677 int chlen = rb_enc_precise_mbclen(p, end, enc);
3678 if (!MBCLEN_CHARFOUND_P(chlen)) {
3679 invalid_multibyte:
3680 errcpy(err, "invalid multibyte character");
3681 return -1;
3682 }
3683 chlen = MBCLEN_CHARFOUND_LEN(chlen);
3684 if (1 < chlen || (*p & 0x80)) {
3685 multibyte:
3686 rb_str_buf_cat(buf, p, chlen);
3687 p += chlen;
3688 if (*encp == 0)
3689 *encp = enc;
3690 else if (*encp != enc) {
3691 errcpy(err, "non ASCII character in UTF-8 regexp");
3692 return -1;
3693 }
3694 continue;
3695 }
3696
3697 switch (c = *p++) {
3698 case '\\':
3699 if (p == end) {
3700 errcpy(err, "too short escape sequence");
3701 return -1;
3702 }
3703 chlen = rb_enc_precise_mbclen(p, end, enc);
3704 if (!MBCLEN_CHARFOUND_P(chlen)) {
3705 goto invalid_multibyte;
3706 }
3707 if ((chlen = MBCLEN_CHARFOUND_LEN(chlen)) > 1) {
3708 /* include the previous backslash */
3709 --p;
3710 ++chlen;
3711 goto multibyte;
3712 }
3713 switch (c = *p++) {
3714 case '1': case '2': case '3':
3715 case '4': case '5': case '6': case '7': /* \O, \OO, \OOO or backref */
3716 {
3717 size_t len = end-(p-1), octlen;
3718 if (ruby_scan_oct(p-1, len < 3 ? len : 3, &octlen) <= 0177) {
3719 /* backref or 7bit octal.
3720 no need to unescape anyway.
3721 re-escaping may break backref */
3722 goto escape_asis;
3723 }
3724 }
3725 /* xxx: How about more than 199 subexpressions? */
3726
3727 case '0': /* \0, \0O, \0OO */
3728
3729 case 'x': /* \xHH */
3730 case 'c': /* \cX, \c\M-X */
3731 case 'C': /* \C-X, \C-\M-X */
3732 case 'M': /* \M-X, \M-\C-X, \M-\cX */
3733 p = p-2;
3734 if (rb_is_usascii_enc(enc)) {
3735 const char *pbeg = p;
3736 int byte = read_escaped_byte(&p, end, err);
3737 if (byte == -1) return -1;
3738 c = byte;
3739 rb_str_buf_cat(buf, pbeg, p-pbeg);
3740 }
3741 else {
3742 if (unescape_escaped_nonascii(&p, end, enc, buf, encp, err) != 0)
3743 return -1;
3744 }
3745 break;
3746
3747 case 'u':
3748 if (p == end) {
3749 errcpy(err, "too short escape sequence");
3750 return -1;
3751 }
3752 if (*p == '{') {
3753 /* \u{H HH HHH HHHH HHHHH HHHHHH ...} */
3754 p++;
3755 if (unescape_unicode_list(&p, end, buf, encp, err) != 0)
3756 return -1;
3757 if (p == end || *p++ != '}') {
3758 errcpy(err, "invalid Unicode list");
3759 return -1;
3760 }
3761 break;
3762 }
3763 else {
3764 /* \uHHHH */
3765 if (unescape_unicode_bmp(&p, end, buf, encp, err) != 0)
3766 return -1;
3767 break;
3768 }
3769
3770 case 'p': /* \p{Hiragana} */
3771 case 'P':
3772 if (!*encp) {
3773 *has_property = 1;
3774 }
3775 goto escape_asis;
3776
3777 default: /* \n, \\, \d, \9, etc. */
3778escape_asis:
3779 smallbuf[0] = '\\';
3780 smallbuf[1] = c;
3781 rb_str_buf_cat(buf, smallbuf, 2);
3782 break;
3783 }
3784 break;
3785
3786 case '#':
3787 if (extended_mode && !in_char_class) {
3788 /* consume and ignore comment in extended regexp */
3789 while ((p < end) && ((c = *p++) != '\n')) {
3790 if ((c & 0x80) && !*encp && enc == rb_utf8_encoding()) {
3791 *encp = enc;
3792 }
3793 }
3794 break;
3795 }
3796 rb_str_buf_cat(buf, (char *)&c, 1);
3797 break;
3798 case '[':
3799 in_char_class++;
3800 rb_str_buf_cat(buf, (char *)&c, 1);
3801 break;
3802 case ']':
3803 if (in_char_class) {
3804 in_char_class--;
3805 }
3806 rb_str_buf_cat(buf, (char *)&c, 1);
3807 break;
3808 case ')':
3809 rb_str_buf_cat(buf, (char *)&c, 1);
3810 if (!in_char_class && recurse) {
3811 if (--parens == 0) {
3812 *pp = p;
3813 return 0;
3814 }
3815 }
3816 break;
3817 case '(':
3818 if (!in_char_class && p + 1 < end && *p == '?') {
3819 if (*(p+1) == '#') {
3820 /* (?# is comment inside any regexp, and content inside should be ignored */
3821 const char *orig_p = p;
3822 int cont = 1;
3823
3824 while (cont && (p < end)) {
3825 switch (c = *p++) {
3826 default:
3827 if (!(c & 0x80)) break;
3828 if (!*encp && enc == rb_utf8_encoding()) {
3829 *encp = enc;
3830 }
3831 --p;
3832 /* fallthrough */
3833 case '\\':
3834 chlen = rb_enc_precise_mbclen(p, end, enc);
3835 if (!MBCLEN_CHARFOUND_P(chlen)) {
3836 goto invalid_multibyte;
3837 }
3838 p += MBCLEN_CHARFOUND_LEN(chlen);
3839 break;
3840 case ')':
3841 cont = 0;
3842 break;
3843 }
3844 }
3845
3846 if (cont) {
3847 /* unterminated (?#, rewind so it is syntax error */
3848 p = orig_p;
3849 c = '(';
3850 rb_str_buf_cat(buf, (char *)&c, 1);
3851 }
3852 break;
3853 }
3854 else {
3855 /* potential change of extended option */
3856 int invert = 0;
3857 int local_extend = 0;
3858 const char *s;
3859
3860 if (recurse) {
3861 parens++;
3862 }
3863
3864 for (s = p+1; s < end; s++) {
3865 switch(*s) {
3866 case 'x':
3867 local_extend = invert ? -1 : 1;
3868 break;
3869 case '-':
3870 invert = 1;
3871 break;
3872 case ':':
3873 case ')':
3874 if (local_extend == 0 ||
3875 (local_extend == -1 && !extended_mode) ||
3876 (local_extend == 1 && extended_mode)) {
3877 /* no changes to extended flag */
3878 goto fallthrough;
3879 }
3880
3881 if (*s == ':') {
3882 /* change extended flag until ')' */
3883 int local_options = options;
3884 if (local_extend == 1) {
3885 local_options |= ONIG_OPTION_EXTEND;
3886 }
3887 else {
3888 local_options &= ~ONIG_OPTION_EXTEND;
3889 }
3890
3891 rb_str_buf_cat(buf, (char *)&c, 1);
3892 int ret = unescape_nonascii0(&p, end, enc, buf, encp,
3893 has_property, err,
3894 local_options, 1);
3895 if (ret < 0) return ret;
3896 goto begin_scan;
3897 }
3898 else {
3899 /* change extended flag for rest of expression */
3900 extended_mode = local_extend == 1;
3901 goto fallthrough;
3902 }
3903 case 'i':
3904 case 'm':
3905 case 'a':
3906 case 'd':
3907 case 'u':
3908 /* other option flags, ignored during scanning */
3909 break;
3910 default:
3911 /* other character, no extended flag change*/
3912 goto fallthrough;
3913 }
3914 }
3915 }
3916 }
3917 else if (!in_char_class && recurse) {
3918 parens++;
3919 }
3920 /* FALLTHROUGH */
3921 default:
3922fallthrough:
3923 rb_str_buf_cat(buf, (char *)&c, 1);
3924 break;
3925 }
3926 }
3927
3928 if (recurse) {
3929 *pp = p;
3930 }
3931 return 0;
3932}
3933
3934static int
3935unescape_nonascii(const char *p, const char *end, rb_encoding *enc,
3936 VALUE buf, rb_encoding **encp, int *has_property,
3937 onig_errmsg_buffer err, int options)
3938{
3939 return unescape_nonascii0(&p, end, enc, buf, encp, has_property,
3940 err, options, 0);
3941}
3942
3943static VALUE
3944rb_reg_preprocess(const char *p, const char *end, rb_encoding *enc,
3945 rb_encoding **fixed_enc, onig_errmsg_buffer err, int options)
3946{
3947 VALUE buf;
3948 int has_property = 0;
3949
3950 buf = rb_str_buf_new(0);
3951
3952 if (rb_enc_asciicompat(enc))
3953 *fixed_enc = 0;
3954 else {
3955 *fixed_enc = enc;
3956 rb_enc_associate(buf, enc);
3957 }
3958
3959 if (unescape_nonascii(p, end, enc, buf, fixed_enc, &has_property, err, options) != 0)
3960 return Qnil;
3961
3962 if (has_property && !*fixed_enc) {
3963 *fixed_enc = enc;
3964 }
3965
3966 if (*fixed_enc) {
3967 rb_enc_associate(buf, *fixed_enc);
3968 }
3969
3970 return buf;
3971}
3972
3973VALUE
3974rb_reg_check_preprocess(VALUE str)
3975{
3976 rb_encoding *fixed_enc = 0;
3977 onig_errmsg_buffer err = "";
3978 VALUE buf;
3979 char *p, *end;
3980 rb_encoding *enc;
3981
3982 StringValue(str);
3983 p = RSTRING_PTR(str);
3984 end = p + RSTRING_LEN(str);
3985 enc = rb_enc_get(str);
3986
3987 buf = rb_reg_preprocess(p, end, enc, &fixed_enc, err, 0);
3988 RB_GC_GUARD(str);
3989
3990 if (NIL_P(buf)) {
3991 return rb_reg_error_desc(str, 0, err);
3992 }
3993 return Qnil;
3994}
3995
3996static VALUE
3997rb_reg_preprocess_dregexp(VALUE ary, int options)
3998{
3999 rb_encoding *fixed_enc = 0;
4000 rb_encoding *regexp_enc = 0;
4001 onig_errmsg_buffer err = "";
4002 int i;
4003 VALUE result = 0;
4004 rb_encoding *ascii8bit = rb_ascii8bit_encoding();
4005
4006 if (RARRAY_LEN(ary) == 0) {
4007 rb_raise(rb_eArgError, "no arguments given");
4008 }
4009
4010 for (i = 0; i < RARRAY_LEN(ary); i++) {
4011 VALUE str = RARRAY_AREF(ary, i);
4012 VALUE buf;
4013 char *p, *end;
4014 rb_encoding *src_enc;
4015
4016 src_enc = rb_enc_get(str);
4017 if (options & ARG_ENCODING_NONE &&
4018 src_enc != ascii8bit) {
4019 if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT)
4020 rb_raise(rb_eRegexpError, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
4021 else
4022 src_enc = ascii8bit;
4023 }
4024
4025 StringValue(str);
4026 p = RSTRING_PTR(str);
4027 end = p + RSTRING_LEN(str);
4028
4029 buf = rb_reg_preprocess(p, end, src_enc, &fixed_enc, err, options);
4030
4031 if (NIL_P(buf))
4032 rb_raise(rb_eArgError, "%s", err);
4033
4034 if (fixed_enc != 0) {
4035 if (regexp_enc != 0 && regexp_enc != fixed_enc) {
4036 rb_raise(rb_eRegexpError, "encoding mismatch in dynamic regexp : %s and %s",
4037 rb_enc_name(regexp_enc), rb_enc_name(fixed_enc));
4038 }
4039 regexp_enc = fixed_enc;
4040 }
4041
4042 if (!result)
4043 result = rb_str_new3(str);
4044 else
4045 rb_str_buf_append(result, str);
4046 }
4047 if (regexp_enc) {
4048 rb_enc_associate(result, regexp_enc);
4049 }
4050
4051 return result;
4052}
4053
4054static void
4055rb_reg_initialize_check(VALUE obj)
4056{
4057 rb_check_frozen(obj);
4058 if (FL_TEST_RAW(obj, RREGEXP_INITIALIZED)) {
4059 rb_raise(rb_eTypeError, "already initialized regexp");
4060 }
4061}
4062
4063static int
4064rb_reg_initialize(VALUE obj, const char *s, rb_len_t len, rb_encoding *enc,
4065 int options, onig_errmsg_buffer err,
4066 const char *sourcefile, int sourceline)
4067{
4068 struct RRegexp *re = RREGEXP(obj);
4069 VALUE unescaped;
4070 rb_encoding *fixed_enc = 0;
4071 rb_encoding *a_enc = rb_ascii8bit_encoding();
4072
4073 rb_reg_initialize_check(obj);
4074
4075 if (rb_enc_dummy_p(enc)) {
4076 errcpy(err, "can't make regexp with dummy encoding");
4077 return -1;
4078 }
4079
4080 unescaped = rb_reg_preprocess(s, s+len, enc, &fixed_enc, err, options);
4081 if (NIL_P(unescaped))
4082 return -1;
4083
4084 if (fixed_enc) {
4085 if ((fixed_enc != enc && (options & ARG_ENCODING_FIXED)) ||
4086 (fixed_enc != a_enc && (options & ARG_ENCODING_NONE))) {
4087 errcpy(err, "incompatible character encoding");
4088 return -1;
4089 }
4090 if (fixed_enc != a_enc) {
4091 options |= ARG_ENCODING_FIXED;
4092 enc = fixed_enc;
4093 }
4094 }
4095 else if (!(options & ARG_ENCODING_FIXED)) {
4096 enc = rb_usascii_encoding();
4097 }
4098
4099 rb_enc_associate((VALUE)re, enc);
4100 if ((options & ARG_ENCODING_FIXED) || fixed_enc) {
4101 re->basic.flags |= KCODE_FIXED;
4102 }
4103 if (options & ARG_ENCODING_NONE) {
4104 re->basic.flags |= REG_ENCODING_NONE;
4105 }
4106
4107 bool success = make_regexp(RREGEXP_PTR(obj), RSTRING_PTR(unescaped), RSTRING_LEN(unescaped), enc,
4108 options & ARG_REG_OPTION_MASK, err,
4109 sourcefile, sourceline);
4110 if (!success) return -1;
4111 FL_SET_RAW(obj, RREGEXP_INITIALIZED);
4112
4113 if (RBASIC_CLASS(obj) == rb_cRegexp) {
4114 OBJ_FREEZE(obj);
4115 }
4116 RB_GC_GUARD(unescaped);
4117 return 0;
4118}
4119
4120static void
4121reg_set_source(VALUE reg, VALUE str, rb_encoding *enc)
4122{
4123 rb_encoding *regenc = rb_enc_get(reg);
4124
4125 if (regenc != enc) {
4126 VALUE dup = rb_str_dup(str);
4127 str = rb_enc_associate(dup, enc = regenc);
4128 }
4129 str = rb_fstring(str);
4130 RB_OBJ_WRITE(reg, &RREGEXP(reg)->src, str);
4131}
4132
4133static int
4134rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
4135 const char *sourcefile, int sourceline)
4136{
4137 int ret;
4138 rb_encoding *str_enc = rb_enc_get(str), *enc = str_enc;
4139 if (options & ARG_ENCODING_NONE) {
4140 rb_encoding *ascii8bit = rb_ascii8bit_encoding();
4141 if (enc != ascii8bit) {
4142 if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
4143 errcpy(err, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
4144 return -1;
4145 }
4146 enc = ascii8bit;
4147 }
4148 }
4149 ret = rb_reg_initialize(obj, RSTRING_PTR(str), RSTRING_LEN(str), enc,
4150 options, err, sourcefile, sourceline);
4151 if (ret == 0) reg_set_source(obj, str, str_enc);
4152 return ret;
4153}
4154
4155VALUE
4156rb_reg_s_alloc(VALUE klass)
4157{
4158 NEWOBJ_OF(re, struct RRegexp, klass, T_REGEXP, sizeof(struct RRegexp_and_re_pattern_buffer));
4159
4160 MEMZERO(RREGEXP_PTR((VALUE)re), struct re_pattern_buffer, 1);
4161 RB_OBJ_WRITE((VALUE)re, &re->src, 0);
4162 re->variants = NULL;
4163
4164 return (VALUE)re;
4165}
4166
4167VALUE
4168rb_reg_alloc(void)
4169{
4170 return rb_reg_s_alloc(rb_cRegexp);
4171}
4172
4173VALUE
4174rb_reg_new_str(VALUE s, int options)
4175{
4176 return rb_reg_init_str(rb_reg_alloc(), s, options);
4177}
4178
4179VALUE
4180rb_reg_init_str(VALUE re, VALUE s, int options)
4181{
4182 onig_errmsg_buffer err = "";
4183
4184 if (rb_reg_initialize_str(re, s, options, err, NULL, 0) != 0) {
4185 rb_reg_raise_str(s, options, err);
4186 }
4187
4188 return re;
4189}
4190
4191static VALUE
4192rb_reg_init_str_enc(VALUE re, VALUE s, rb_encoding *enc, int options)
4193{
4194 onig_errmsg_buffer err = "";
4195
4196 if (rb_reg_initialize(re, RSTRING_PTR(s), RSTRING_LEN(s),
4197 enc, options, err, NULL, 0) != 0) {
4198 rb_reg_raise_str(s, options, err);
4199 }
4200 reg_set_source(re, s, enc);
4201
4202 return re;
4203}
4204
4205VALUE
4206rb_reg_new_from_values(rb_len_t cnt, const VALUE *elements, int opt)
4207{
4208 const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, elements);
4209 VALUE val = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
4210 rb_ary_clear(ary);
4211 return val;
4212}
4213
4214VALUE
4215rb_enc_reg_new(const char *s, rb_len_t len, rb_encoding *enc, int options)
4216{
4217 VALUE re = rb_reg_alloc();
4218 onig_errmsg_buffer err = "";
4219
4220 if (rb_reg_initialize(re, s, len, enc, options, err, NULL, 0) != 0) {
4221 rb_enc_reg_raise(s, len, enc, options, err);
4222 }
4223 RB_OBJ_WRITE(re, &RREGEXP(re)->src, rb_fstring(rb_enc_str_new(s, len, enc)));
4224
4225 return re;
4226}
4227
4228VALUE
4229rb_reg_new(const char *s, rb_len_t len, int options)
4230{
4231 return rb_enc_reg_new(s, len, rb_ascii8bit_encoding(), options);
4232}
4233
4234VALUE
4235rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
4236{
4237 VALUE re = rb_reg_alloc();
4238 onig_errmsg_buffer err = "";
4239
4240 if (!str) str = rb_str_new(0,0);
4241 if (rb_reg_initialize_str(re, str, options, err, sourcefile, sourceline) != 0) {
4242 rb_set_errinfo(rb_reg_error_desc(str, options, err));
4243 return Qnil;
4244 }
4245 return re;
4246}
4247
4248static VALUE reg_cache;
4249
4250VALUE
4252{
4253 if (rb_ractor_main_p()) {
4254 if (reg_cache && RREGEXP_SRC_LEN(reg_cache) == RSTRING_LEN(str)
4255 && ENCODING_GET(reg_cache) == ENCODING_GET(str)
4256 && memcmp(RREGEXP_SRC_PTR(reg_cache), RSTRING_PTR(str), RSTRING_LEN(str)) == 0)
4257 return reg_cache;
4258
4259 return reg_cache = rb_reg_new_str(str, 0);
4260 }
4261 else {
4262 return rb_reg_new_str(str, 0);
4263 }
4264}
4265
4266static st_index_t reg_hash(VALUE re);
4267/*
4268 * call-seq:
4269 * hash -> integer
4270 *
4271 * Returns the integer hash value for +self+.
4272 *
4273 * Related: Object#hash.
4274 *
4275 */
4276
4277VALUE
4278rb_reg_hash(VALUE re)
4279{
4280 st_index_t hashval = reg_hash(re);
4281 return ST2FIX(hashval);
4282}
4283
4284static st_index_t
4285reg_hash(VALUE re)
4286{
4287 st_index_t hashval;
4288
4289 rb_reg_check(re);
4290 hashval = RREGEXP_PTR(re)->options;
4291 hashval = rb_hash_uint(hashval, rb_memhash(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re)));
4292 return rb_hash_end(hashval);
4293}
4294
4295
4296/*
4297 * call-seq:
4298 * self == other -> true or false
4299 *
4300 * Returns whether +other+ is another \Regexp whose pattern,
4301 * flags, and encoding are the same as +self+:
4302 *
4303 * /foo/ == Regexp.new('foo') # => true
4304 * /foo/ == /foo/i # => false
4305 * /foo/ == Regexp.new('food') # => false
4306 * /foo/ == Regexp.new("abc".force_encoding("euc-jp")) # => false
4307 *
4308 */
4309
4310VALUE
4311rb_reg_equal(VALUE re1, VALUE re2)
4312{
4313 if (re1 == re2) return Qtrue;
4314 if (!RB_TYPE_P(re2, T_REGEXP)) return Qfalse;
4315 rb_reg_check(re1); rb_reg_check(re2);
4316
4317 // src is a fstring, so a pointer comparison is enough
4318 RUBY_ASSERT(FL_TEST_RAW(RREGEXP_SRC(re1), RSTRING_FSTR));
4319 RUBY_ASSERT(FL_TEST_RAW(RREGEXP_SRC(re2), RSTRING_FSTR));
4320
4321 if (FL_TEST(re1, KCODE_FIXED) != FL_TEST(re2, KCODE_FIXED)) return Qfalse;
4322 if (RREGEXP_PTR(re1)->options != RREGEXP_PTR(re2)->options) return Qfalse;
4323 if (RREGEXP_SRC_LEN(re1) != RREGEXP_SRC_LEN(re2)) return Qfalse;
4324 if (ENCODING_GET(re1) != ENCODING_GET(re2)) return Qfalse;
4325
4326 if (RREGEXP_SRC(re1) == RREGEXP_SRC(re2)) return Qtrue;
4327 if (RREGEXP_SRC_PTR(re1) == RREGEXP_SRC_PTR(re2)) return Qtrue;
4328 return RBOOL(memcmp(RREGEXP_SRC_PTR(re1), RREGEXP_SRC_PTR(re2), RREGEXP_SRC_LEN(re1)) == 0);
4329}
4330
4331/*
4332 * :markup: markdown
4333 *
4334 * call-seq:
4335 * hash -> integer
4336 *
4337 * Returns the integer hash value for `self`,
4338 * based on its target string, regexp, match, and captures.
4339 *
4340 * See also Object#hash.
4341 *
4342 */
4343
4344static VALUE
4345match_hash(VALUE match)
4346{
4347 st_index_t hashval;
4348
4349 match_check(match);
4350 hashval = rb_hash_start(rb_str_hash(RMATCH(match)->str));
4351 hashval = rb_hash_uint(hashval, reg_hash(match_regexp(match)));
4352 int num_regs = RMATCH_NREGS(match);
4353 hashval = rb_hash_uint(hashval, num_regs);
4354 hashval = rb_hash_uint(hashval, rb_memhash(RMATCH_BEG_PTR(match), num_regs * sizeof(OnigPosition)));
4355 hashval = rb_hash_uint(hashval, rb_memhash(RMATCH_END_PTR(match), num_regs * sizeof(OnigPosition)));
4356 hashval = rb_hash_end(hashval);
4357 return ST2FIX(hashval);
4358}
4359
4360/*
4361 * :markup: markdown
4362 *
4363 * call-seq:
4364 * self == object -> true or false
4365 *
4366 * Returns whether `object` is a \MatchData object
4367 * whose #string, #regexp, and #begin values are the same as those of `self`:
4368 *
4369 * ```ruby
4370 * regexp = /a/
4371 * s = 'aba'
4372 * match0 = regexp.match(s)
4373 * match1 = regexp.match(s, 2)
4374 * match0[0] # => "a"
4375 * match1[0] # => "a"
4376 * match0.begin(0) # => 0
4377 * match1.begin(0) # => 2
4378 * match0 == match0 # => true
4379 * match0 == match1 # => false
4380 * ```
4381 *
4382 */
4383
4384static VALUE
4385match_equal(VALUE match1, VALUE match2)
4386{
4387 if (match1 == match2) return Qtrue;
4388 if (!RB_TYPE_P(match2, T_MATCH)) return Qfalse;
4389 if (!RMATCH(match1)->regexp || !RMATCH(match2)->regexp) return Qfalse;
4390 if (!rb_str_equal(RMATCH(match1)->str, RMATCH(match2)->str)) return Qfalse;
4391 if (!rb_reg_equal(match_regexp(match1), match_regexp(match2))) return Qfalse;
4392 int num_regs = RMATCH_NREGS(match1);
4393 if (num_regs != RMATCH_NREGS(match2)) return Qfalse;
4394 if (memcmp(RMATCH_BEG_PTR(match1), RMATCH_BEG_PTR(match2), num_regs * sizeof(OnigPosition))) return Qfalse;
4395 if (memcmp(RMATCH_END_PTR(match1), RMATCH_END_PTR(match2), num_regs * sizeof(OnigPosition))) return Qfalse;
4396 return Qtrue;
4397}
4398
4399/*
4400 * :markup: markdown
4401 *
4402 * call-seq:
4403 * integer_at(n, radix = 10) -> integer or nil
4404 * integer_at(name, radix = 10) -> integer or nil
4405 *
4406 * Returns a captured substring converted to an integer;
4407 * the substring is interpreted as a numeric string in the given `radix`.
4408 *
4409 * With integer index `n` given,
4410 * returns the `n`th capture converted to an integer:
4411 *
4412 * ```ruby
4413 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
4414 * match = '2026-12-25'.match(regexp)
4415 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
4416 * match[0] # => "2026-12-25"
4417 * match.integer_at(0) # => 2026 # Stops interpreting at the hyphen.
4418 * match.integer_at(1) # => 2026
4419 * match.integer_at(2) # => 12
4420 * match.integer_at(3) # => 25
4421 * match.integer_at(-1) # => 25 # For negative n, counts backwards in the captures.
4422 * match.integer_at(4) # => nil
4423 * ```
4424 *
4425 * With string or symbol `name` given,
4426 * returns the named capture converted to an integer:
4427 *
4428 * ```ruby
4429 * regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
4430 * match = '2026-12-25'.match(regexp)
4431 * # => #<MatchData "2026-12-25" year:"2026" month:"12" day:"25">
4432 * match.integer_at(:year) # => 2026
4433 * match.integer_at('month') # => 12
4434 * match.integer_at(:nosuch) # Raises IndexError: undefined group name reference: nosuch.
4435 * ```
4436 *
4437 * Returns `nil` if there were no captures.
4438 *
4439 * For both forms above, the string is converted in the given `radix`:
4440 *
4441 * ```ruby
4442 * match = /\d+/.match('11')
4443 * # => #<MatchData "11">
4444 * match.integer_at(0) # => 11
4445 * match.integer_at(0, 2) # => 3
4446 * match.integer_at(0, 8) # => 9
4447 * match.integer_at(0, 16) # => 17
4448 * match.integer_at(0, 1) # Raises ArgumentError: invalid radix 1.
4449 * ```
4450 *
4451 * Related: MatchData#[], String#to_i.
4452 */
4453static VALUE
4454match_integer_at(int argc, VALUE *argv, VALUE match)
4455{
4456 match_check(match);
4457
4458 int base = 10;
4459 VALUE idx;
4460 int nth;
4461
4462 argc = rb_check_arity(argc, 1, 2);
4463 if (FIXNUM_P(idx = argv[0])) {
4464 nth = NUM2INT(idx);
4465 }
4466 else if ((nth = namev_to_backref_number(match, idx)) < 0) {
4467 name_to_backref_error(idx);
4468 }
4469
4470 if (argc > 1 && (base = NUM2INT(argv[1])) < 0) {
4471 rb_raise(rb_eArgError, "invalid radix %d", base);
4472 }
4473
4474 if (nth >= RMATCH_NREGS(match)) return Qnil;
4475 if (nth < 0 && (nth += RMATCH_NREGS(match)) <= 0) return Qnil;
4476
4477 rb_len_t start = RMATCH_BEG(match, nth), end = RMATCH_END(match, nth);
4478 if (start < 0) return Qnil;
4479 RUBY_ASSERT(start <= end, "%"PRIdLEN" > %"PRIdLEN, start, end);
4480
4481 VALUE str = RMATCH(match)->str;
4482 RUBY_ASSERT(end <= RSTRING_LEN(str), "%"PRIdLEN" > %"PRIdLEN, end, RSTRING_LEN(str));
4483
4484 char *endp;
4485 return rb_int_parse_cstr(RSTRING_PTR(str) + start, end - start, &endp, NULL,
4486 base, RB_INT_PARSE_DEFAULT);
4487}
4488
4489static VALUE
4490reg_operand(VALUE s, int check)
4491{
4492 if (SYMBOL_P(s)) {
4493 return rb_sym2str(s);
4494 }
4495 else if (RB_TYPE_P(s, T_STRING)) {
4496 return s;
4497 }
4498 else {
4499 return check ? rb_str_to_str(s) : rb_check_string_type(s);
4500 }
4501}
4502
4503static rb_len_t
4504reg_match_pos(VALUE re, VALUE *strp, rb_len_t pos, VALUE* set_match)
4505{
4506 VALUE str = *strp;
4507
4508 if (NIL_P(str)) {
4509 rb_backref_set(Qnil);
4510 return -1;
4511 }
4512 *strp = str = reg_operand(str, TRUE);
4513 if (pos != 0) {
4514 if (pos < 0) {
4515 VALUE l = rb_str_length(str);
4516 pos += NUM2INT(l);
4517 if (pos < 0) {
4518 rb_backref_set(Qnil);
4519 return pos;
4520 }
4521 }
4522 pos = rb_str_offset(str, pos);
4523 }
4524 return rb_reg_search_set_match(re, str, pos, 0, 1, set_match);
4525}
4526
4527/*
4528 * call-seq:
4529 * self =~ other -> integer or nil
4530 *
4531 * Returns the integer index (in characters) of the first match
4532 * for +self+ and +other+, or +nil+ if none;
4533 * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
4534 *
4535 * /at/ =~ 'input data' # => 7
4536 * $~ # => #<MatchData "at">
4537 * /ax/ =~ 'input data' # => nil
4538 * $~ # => nil
4539 *
4540 * Assigns named captures to local variables of the same names
4541 * if and only if +self+:
4542 *
4543 * - Is a regexp literal;
4544 * see {Regexp Literals}[rdoc-ref:syntax/literals.rdoc@Regexp+Literals].
4545 * - Does not contain interpolations;
4546 * see {Regexp interpolation}[rdoc-ref:Regexp@Interpolation+Mode].
4547 * - Is at the left of the expression.
4548 *
4549 * Example:
4550 *
4551 * /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ ' x = y '
4552 * p lhs # => "x"
4553 * p rhs # => "y"
4554 *
4555 * Assigns +nil+ if not matched:
4556 *
4557 * /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ ' x = '
4558 * p lhs # => nil
4559 * p rhs # => nil
4560 *
4561 * Does not make local variable assignments if +self+ is not a regexp literal:
4562 *
4563 * r = /(?<foo>\w+)\s*=\s*(?<foo>\w+)/
4564 * r =~ ' x = y '
4565 * p foo # Undefined local variable
4566 * p bar # Undefined local variable
4567 *
4568 * The assignment does not occur if the regexp is not at the left:
4569 *
4570 * ' x = y ' =~ /(?<foo>\w+)\s*=\s*(?<foo>\w+)/
4571 * p foo, foo # Undefined local variables
4572 *
4573 * A regexp interpolation, <tt>#{}</tt>, also disables
4574 * the assignment:
4575 *
4576 * r = /(?<foo>\w+)/
4577 * /(?<foo>\w+)\s*=\s*#{r}/ =~ 'x = y'
4578 * p foo # Undefined local variable
4579 *
4580 */
4581
4582VALUE
4583rb_reg_match(VALUE re, VALUE str)
4584{
4585 rb_len_t pos = reg_match_pos(re, &str, 0, NULL);
4586 if (pos < 0) return Qnil;
4587 pos = rb_str_sublen(str, pos);
4588 return LEN2NUM(pos);
4589}
4590
4591/*
4592 * call-seq:
4593 * self === other -> true or false
4594 *
4595 * Returns whether +self+ finds a match in +other+:
4596 *
4597 * /^[a-z]*$/ === 'HELLO' # => false
4598 * /^[A-Z]*$/ === 'HELLO' # => true
4599 *
4600 * This method is called in case statements:
4601 *
4602 * s = 'HELLO'
4603 * case s
4604 * when /\A[a-z]*\z/; print "Lower case\n"
4605 * when /\A[A-Z]*\z/; print "Upper case\n"
4606 * else print "Mixed case\n"
4607 * end # => "Upper case"
4608 *
4609 */
4610
4611static VALUE
4612rb_reg_eqq(VALUE re, VALUE str)
4613{
4614 rb_len_t start;
4615
4616 str = reg_operand(str, FALSE);
4617 if (NIL_P(str)) {
4618 rb_backref_set(Qnil);
4619 return Qfalse;
4620 }
4621 start = rb_reg_search(re, str, 0, 0);
4622 return RBOOL(start >= 0);
4623}
4624
4625
4626/*
4627 * call-seq:
4628 * ~ rxp -> integer or nil
4629 *
4630 * Equivalent to <tt><i>rxp</i> =~ $_</tt>:
4631 *
4632 * $_ = "input data"
4633 * ~ /at/ # => 7
4634 *
4635 */
4636
4637VALUE
4638rb_reg_match2(VALUE re)
4639{
4640 rb_len_t start;
4641 VALUE line = rb_lastline_get();
4642
4643 if (!RB_TYPE_P(line, T_STRING)) {
4644 rb_backref_set(Qnil);
4645 return Qnil;
4646 }
4647
4648 start = rb_reg_search(re, line, 0, 0);
4649 if (start < 0) {
4650 return Qnil;
4651 }
4652 start = rb_str_sublen(line, start);
4653 return LEN2NUM(start);
4654}
4655
4656
4657/*
4658 * call-seq:
4659 * match(string, offset = 0) -> matchdata or nil
4660 * match(string, offset = 0) {|matchdata| ... } -> object
4661 *
4662 * With no block given, returns the MatchData object
4663 * that describes the match, if any, or +nil+ if none;
4664 * the search begins at the given character +offset+ in +string+:
4665 *
4666 * /abra/.match('abracadabra') # => #<MatchData "abra">
4667 * /abra/.match('abracadabra', 4) # => #<MatchData "abra">
4668 * /abra/.match('abracadabra', 8) # => nil
4669 * /abra/.match('abracadabra', 800) # => nil
4670 *
4671 * string = "\u{5d0 5d1 5e8 5d0}cadabra"
4672 * /abra/.match(string, 7) #=> #<MatchData "abra">
4673 * /abra/.match(string, 8) #=> nil
4674 * /abra/.match(string.b, 8) #=> #<MatchData "abra">
4675 *
4676 * With a block given, calls the block if and only if a match is found;
4677 * returns the block's value:
4678 *
4679 * /abra/.match('abracadabra') {|matchdata| p matchdata }
4680 * # => #<MatchData "abra">
4681 * /abra/.match('abracadabra', 4) {|matchdata| p matchdata }
4682 * # => #<MatchData "abra">
4683 * /abra/.match('abracadabra', 8) {|matchdata| p matchdata }
4684 * # => nil
4685 * /abra/.match('abracadabra', 8) {|marchdata| fail 'Cannot happen' }
4686 * # => nil
4687 *
4688 * Output (from the first two blocks above):
4689 *
4690 * #<MatchData "abra">
4691 * #<MatchData "abra">
4692 *
4693 * /(.)(.)(.)/.match("abc")[2] # => "b"
4694 * /(.)(.)/.match("abc", 1)[2] # => "c"
4695 *
4696 */
4697
4698static VALUE
4699rb_reg_match_m(int argc, VALUE *argv, VALUE re)
4700{
4701 VALUE result = Qnil, str, initpos;
4702 rb_len_t pos;
4703
4704 if (rb_scan_args(argc, argv, "11", &str, &initpos) == 2) {
4705 pos = NUM2LEN(initpos);
4706 }
4707 else {
4708 pos = 0;
4709 }
4710
4711 pos = reg_match_pos(re, &str, pos, &result);
4712 if (pos < 0) {
4713 return Qnil;
4714 }
4715 rb_match_busy(result);
4716 if (!NIL_P(result) && rb_block_given_p()) {
4717 return rb_yield(result);
4718 }
4719 return result;
4720}
4721
4722/*
4723 * call-seq:
4724 * match?(string) -> true or false
4725 * match?(string, offset = 0) -> true or false
4726 *
4727 * Returns <code>true</code> or <code>false</code> to indicate whether the
4728 * regexp is matched or not without updating $~ and other related variables.
4729 * If the second parameter is present, it specifies the position in the string
4730 * to begin the search.
4731 *
4732 * /R.../.match?("Ruby") # => true
4733 * /R.../.match?("Ruby", 1) # => false
4734 * /P.../.match?("Ruby") # => false
4735 * $& # => nil
4736 */
4737
4738static VALUE
4739rb_reg_match_m_p(int argc, VALUE *argv, VALUE re)
4740{
4741 rb_len_t pos = rb_check_arity(argc, 1, 2) > 1 ? NUM2LEN(argv[1]) : 0;
4742 return rb_reg_match_p(re, argv[0], pos);
4743}
4744
4745VALUE
4746rb_reg_match_p(VALUE re, VALUE str, rb_len_t pos)
4747{
4748 if (NIL_P(str)) return Qfalse;
4749 str = SYMBOL_P(str) ? rb_sym2str(str) : StringValue(str);
4750 if (pos) {
4751 if (pos < 0) {
4752 pos += NUM2LEN(rb_str_length(str));
4753 if (pos < 0) return Qfalse;
4754 }
4755 if (pos > 0) {
4756 rb_len_t len = 1;
4757 const char *beg = rb_str_subpos(str, pos, &len);
4758 if (!beg) return Qfalse;
4759 pos = beg - RSTRING_PTR(str);
4760 }
4761 }
4762
4763 struct reg_onig_search_args args = {
4764 .pos = pos,
4765 .range = RSTRING_LEN(str),
4766 };
4767
4768 return rb_reg_onig_match(re, str, reg_onig_search, &args, NULL) == ONIG_MISMATCH ? Qfalse : Qtrue;
4769}
4770
4771/*
4772 * Document-method: compile
4773 *
4774 * Alias for Regexp.new
4775 */
4776
4777static int
4778str_to_option(VALUE str)
4779{
4780 int flag = 0;
4781 const char *ptr;
4782 rb_len_t len;
4783 str = rb_check_string_type(str);
4784 if (NIL_P(str)) return -1;
4785 RSTRING_GETMEM(str, ptr, len);
4786 for (rb_len_t i = 0; i < len; ++i) {
4787 int f = char_to_option(ptr[i]);
4788 if (!f) {
4789 rb_raise(rb_eArgError, "unknown regexp option: %"PRIsVALUE, str);
4790 }
4791 flag |= f;
4792 }
4793 return flag;
4794}
4795
4796static void
4797set_timeout(rb_hrtime_t *hrt, VALUE timeout)
4798{
4799 double timeout_d = NIL_P(timeout) ? 0.0 : NUM2DBL(timeout);
4800 if (!NIL_P(timeout) && !(timeout_d > 0)) {
4801 rb_raise(rb_eArgError, "invalid timeout: %"PRIsVALUE, timeout);
4802 }
4803 double2hrtime(hrt, timeout_d);
4804}
4805
4806static VALUE
4807reg_copy(VALUE copy, VALUE orig)
4808{
4809 int r;
4810 rb_reg_initialize_check(copy);
4811 if ((r = onig_reg_copy_body(RREGEXP_PTR(copy), RREGEXP_PTR(orig))) != 0) {
4812 /* ONIGERR_MEMORY only */
4813 rb_raise(rb_eRegexpError, "%s", onig_error_code_to_format(r));
4814 }
4815 FL_SET_RAW(copy, RREGEXP_INITIALIZED);
4816
4817 RB_OBJ_WRITE(copy, &RREGEXP(copy)->src, RREGEXP(orig)->src);
4818 RREGEXP_PTR(copy)->timelimit = RREGEXP_PTR(orig)->timelimit;
4819 rb_enc_copy(copy, orig);
4820 FL_SET_RAW(copy, FL_TEST_RAW(orig, KCODE_FIXED|REG_ENCODING_NONE));
4821 if (RBASIC_CLASS(copy) == rb_cRegexp) {
4822 OBJ_FREEZE(copy);
4823 }
4824
4825 return copy;
4826}
4827
4828struct reg_init_args {
4829 VALUE str;
4830 VALUE timeout;
4831 rb_encoding *enc;
4832 int flags;
4833};
4834
4835static VALUE reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args);
4836static VALUE reg_init_args(VALUE self, VALUE str, rb_encoding *enc, int flags);
4837
4838/*
4839 * call-seq:
4840 * Regexp.new(string, options = 0, timeout: nil) -> regexp
4841 * Regexp.new(regexp, timeout: nil) -> regexp
4842 *
4843 * With argument +string+ given, returns a new regexp with the given string
4844 * and options:
4845 *
4846 * r = Regexp.new('foo') # => /foo/
4847 * r.source # => "foo"
4848 * r.options # => 0
4849 *
4850 * Optional argument +options+ is one of the following:
4851 *
4852 * - A String of options:
4853 *
4854 * Regexp.new('foo', 'i') # => /foo/i
4855 * Regexp.new('foo', 'im') # => /foo/im
4856 *
4857 * - The bit-wise OR of one or more of the constants
4858 * Regexp::EXTENDED, Regexp::IGNORECASE, Regexp::MULTILINE, and
4859 * Regexp::NOENCODING:
4860 *
4861 * Regexp.new('foo', Regexp::IGNORECASE) # => /foo/i
4862 * Regexp.new('foo', Regexp::EXTENDED) # => /foo/x
4863 * Regexp.new('foo', Regexp::MULTILINE) # => /foo/m
4864 * Regexp.new('foo', Regexp::NOENCODING) # => /foo/n
4865 * flags = Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE
4866 * Regexp.new('foo', flags) # => /foo/mix
4867 *
4868 * - +nil+ or +false+, which is ignored.
4869 * - Any other truthy value, in which case the regexp will be
4870 * case-insensitive.
4871 *
4872 * If optional keyword argument +timeout+ is given,
4873 * its float value overrides the timeout interval for the class,
4874 * Regexp.timeout.
4875 * If +nil+ is passed as +timeout, it uses the timeout interval
4876 * for the class, Regexp.timeout.
4877 *
4878 * With argument +regexp+ given, returns a new regexp. The source,
4879 * options, timeout are the same as +regexp+. +options+ and +n_flag+
4880 * arguments are ineffective. The timeout can be overridden by
4881 * +timeout+ keyword.
4882 *
4883 * options = Regexp::MULTILINE
4884 * r = Regexp.new('foo', options, timeout: 1.1) # => /foo/m
4885 * r2 = Regexp.new(r) # => /foo/m
4886 * r2.timeout # => 1.1
4887 * r3 = Regexp.new(r, timeout: 3.14) # => /foo/m
4888 * r3.timeout # => 3.14
4889 *
4890 */
4891
4892static VALUE
4893rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
4894{
4895 struct reg_init_args args;
4896 VALUE re = reg_extract_args(argc, argv, &args);
4897
4898 if (NIL_P(re)) {
4899 reg_init_args(self, args.str, args.enc, args.flags);
4900 }
4901 else {
4902 reg_copy(self, re);
4903 }
4904
4905 set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout);
4906 if (RBASIC_CLASS(self) == rb_cRegexp) {
4907 OBJ_FREEZE(self);
4908 }
4909
4910 return self;
4911}
4912
4913static VALUE
4914reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
4915{
4916 int flags = 0;
4917 rb_encoding *enc = 0;
4918 VALUE str, src, opts = Qundef, kwargs;
4919 VALUE re = Qnil;
4920
4921 rb_scan_args(argc, argv, "11:", &src, &opts, &kwargs);
4922
4923 args->timeout = Qnil;
4924 if (!NIL_P(kwargs)) {
4925 static ID keywords[1];
4926 if (!keywords[0]) {
4927 keywords[0] = rb_intern_const("timeout");
4928 }
4929 rb_get_kwargs(kwargs, keywords, 0, 1, &args->timeout);
4930 }
4931
4932 if (RB_TYPE_P(src, T_REGEXP)) {
4933 re = src;
4934
4935 if (!NIL_P(opts)) {
4936 rb_warn("flags ignored");
4937 }
4938 rb_reg_check(re);
4939 flags = rb_reg_options(re);
4940 str = RREGEXP_SRC(re);
4941 }
4942 else {
4943 if (!NIL_P(opts)) {
4944 int f;
4945 if (FIXNUM_P(opts)) flags = FIX2INT(opts);
4946 else if ((f = str_to_option(opts)) >= 0) flags = f;
4947 else if (rb_bool_expected(opts, "ignorecase", FALSE))
4948 flags = ONIG_OPTION_IGNORECASE;
4949 }
4950 str = StringValue(src);
4951 }
4952 args->str = str;
4953 args->enc = enc;
4954 args->flags = flags;
4955 return re;
4956}
4957
4958static VALUE
4959reg_init_args(VALUE self, VALUE str, rb_encoding *enc, int flags)
4960{
4961 if (enc && rb_enc_get(str) != enc)
4962 rb_reg_init_str_enc(self, str, enc, flags);
4963 else
4964 rb_reg_init_str(self, str, flags);
4965 return self;
4966}
4967
4968VALUE
4969rb_reg_quote(VALUE str)
4970{
4971 rb_encoding *enc = rb_enc_get(str);
4972 char *s, *send, *t;
4973 VALUE tmp;
4974 int c, clen;
4975 int ascii_only = rb_enc_str_asciionly_p(str);
4976
4977 s = RSTRING_PTR(str);
4978 send = s + RSTRING_LEN(str);
4979 while (s < send) {
4980 c = rb_enc_ascget(s, send, &clen, enc);
4981 if (c == -1) {
4982 s += mbclen(s, send, enc);
4983 continue;
4984 }
4985 switch (c) {
4986 case '[': case ']': case '{': case '}':
4987 case '(': case ')': case '|': case '-':
4988 case '*': case '.': case '\\':
4989 case '?': case '+': case '^': case '$':
4990 case ' ': case '#':
4991 case '\t': case '\f': case '\v': case '\n': case '\r':
4992 goto meta_found;
4993 }
4994 s += clen;
4995 }
4996 tmp = rb_str_new3(str);
4997 if (ascii_only) {
4998 rb_enc_associate(tmp, rb_usascii_encoding());
4999 }
5000 return tmp;
5001
5002 meta_found:
5003 tmp = rb_str_new(0, RSTRING_LEN(str)*2);
5004 if (ascii_only) {
5005 rb_enc_associate(tmp, rb_usascii_encoding());
5006 }
5007 else {
5008 rb_enc_copy(tmp, str);
5009 }
5010 t = RSTRING_PTR(tmp);
5011 /* copy upto metacharacter */
5012 const char *p = RSTRING_PTR(str);
5013 memcpy(t, p, s - p);
5014 t += s - p;
5015
5016 while (s < send) {
5017 c = rb_enc_ascget(s, send, &clen, enc);
5018 if (c == -1) {
5019 int n = mbclen(s, send, enc);
5020
5021 while (n--)
5022 *t++ = *s++;
5023 continue;
5024 }
5025 s += clen;
5026 switch (c) {
5027 case '[': case ']': case '{': case '}':
5028 case '(': case ')': case '|': case '-':
5029 case '*': case '.': case '\\':
5030 case '?': case '+': case '^': case '$':
5031 case '#':
5032 t += rb_enc_mbcput('\\', t, enc);
5033 break;
5034 case ' ':
5035 t += rb_enc_mbcput('\\', t, enc);
5036 t += rb_enc_mbcput(' ', t, enc);
5037 continue;
5038 case '\t':
5039 t += rb_enc_mbcput('\\', t, enc);
5040 t += rb_enc_mbcput('t', t, enc);
5041 continue;
5042 case '\n':
5043 t += rb_enc_mbcput('\\', t, enc);
5044 t += rb_enc_mbcput('n', t, enc);
5045 continue;
5046 case '\r':
5047 t += rb_enc_mbcput('\\', t, enc);
5048 t += rb_enc_mbcput('r', t, enc);
5049 continue;
5050 case '\f':
5051 t += rb_enc_mbcput('\\', t, enc);
5052 t += rb_enc_mbcput('f', t, enc);
5053 continue;
5054 case '\v':
5055 t += rb_enc_mbcput('\\', t, enc);
5056 t += rb_enc_mbcput('v', t, enc);
5057 continue;
5058 }
5059 t += rb_enc_mbcput(c, t, enc);
5060 }
5061 rb_str_resize(tmp, t - RSTRING_PTR(tmp));
5062 return tmp;
5063}
5064
5065
5066/*
5067 * call-seq:
5068 * Regexp.escape(string) -> new_string
5069 *
5070 * Returns a new string that escapes any characters
5071 * that have special meaning in a regular expression:
5072 *
5073 * s = Regexp.escape('\*?{}.') # => "\\\\\\*\\?\\{\\}\\."
5074 *
5075 * For any string +s+, this call returns a MatchData object:
5076 *
5077 * r = Regexp.new(Regexp.escape(s)) # => /\\\\\\\*\\\?\\\{\\\}\\\./
5078 * r.match(s) # => #<MatchData "\\\\\\*\\?\\{\\}\\.">
5079 *
5080 */
5081
5082static VALUE
5083rb_reg_s_quote(VALUE c, VALUE str)
5084{
5085 return rb_reg_quote(reg_operand(str, TRUE));
5086}
5087
5088int
5089rb_reg_options(VALUE re)
5090{
5091 int options;
5092
5093 rb_reg_check(re);
5094 options = RREGEXP_PTR(re)->options & ARG_REG_OPTION_MASK;
5095 if (RBASIC(re)->flags & KCODE_FIXED) options |= ARG_ENCODING_FIXED;
5096 if (RBASIC(re)->flags & REG_ENCODING_NONE) options |= ARG_ENCODING_NONE;
5097 return options;
5098}
5099
5100static VALUE
5101rb_check_regexp_type(VALUE re)
5102{
5103 return rb_check_convert_type(re, T_REGEXP, "Regexp", "to_regexp");
5104}
5105
5106/*
5107 * call-seq:
5108 * Regexp.try_convert(object) -> regexp or nil
5109 *
5110 * Returns +object+ if it is a regexp:
5111 *
5112 * Regexp.try_convert(/re/) # => /re/
5113 *
5114 * Otherwise if +object+ responds to <tt>:to_regexp</tt>,
5115 * calls <tt>object.to_regexp</tt> and returns the result.
5116 *
5117 * Returns +nil+ if +object+ does not respond to <tt>:to_regexp</tt>.
5118 *
5119 * Regexp.try_convert('re') # => nil
5120 *
5121 * Raises an exception unless <tt>object.to_regexp</tt> returns a regexp.
5122 *
5123 */
5124static VALUE
5125rb_reg_s_try_convert(VALUE dummy, VALUE re)
5126{
5127 return rb_check_regexp_type(re);
5128}
5129
5130static VALUE
5131rb_reg_s_union(VALUE self, VALUE args0)
5132{
5133 rb_len_t argc = RARRAY_LEN(args0);
5134
5135 if (argc == 0) {
5136 VALUE args[1];
5137 args[0] = rb_str_new2("(?!)");
5138 return rb_class_new_instance(1, args, rb_cRegexp);
5139 }
5140 else if (argc == 1) {
5141 VALUE arg = rb_ary_entry(args0, 0);
5142 VALUE re = rb_check_regexp_type(arg);
5143 if (!NIL_P(re))
5144 return re;
5145 else {
5146 VALUE quoted;
5147 quoted = rb_reg_s_quote(Qnil, arg);
5148 return rb_reg_new_str(quoted, 0);
5149 }
5150 }
5151 else {
5152 int i;
5153 VALUE source = rb_str_buf_new(0);
5154 rb_encoding *result_enc;
5155
5156 int has_asciionly = 0;
5157 rb_encoding *has_ascii_compat_fixed = 0;
5158 rb_encoding *has_ascii_incompat = 0;
5159
5160 for (i = 0; i < argc; i++) {
5161 volatile VALUE v;
5162 VALUE e = rb_ary_entry(args0, i);
5163
5164 if (0 < i)
5165 rb_str_buf_cat_ascii(source, "|");
5166
5167 v = rb_check_regexp_type(e);
5168 if (!NIL_P(v)) {
5169 rb_encoding *enc = rb_enc_get(v);
5170 if (!rb_enc_asciicompat(enc)) {
5171 if (!has_ascii_incompat)
5172 has_ascii_incompat = enc;
5173 else if (has_ascii_incompat != enc)
5174 rb_raise(rb_eArgError, "incompatible encodings: %s and %s",
5175 rb_enc_name(has_ascii_incompat), rb_enc_name(enc));
5176 }
5177 else if (rb_reg_fixed_encoding_p(v)) {
5178 if (!has_ascii_compat_fixed)
5179 has_ascii_compat_fixed = enc;
5180 else if (has_ascii_compat_fixed != enc)
5181 rb_raise(rb_eArgError, "incompatible encodings: %s and %s",
5182 rb_enc_name(has_ascii_compat_fixed), rb_enc_name(enc));
5183 }
5184 else {
5185 has_asciionly = 1;
5186 }
5187 v = rb_reg_str_with_term(v, -1);
5188 }
5189 else {
5190 rb_encoding *enc;
5191 StringValue(e);
5192 enc = rb_enc_get(e);
5193 if (!rb_enc_asciicompat(enc)) {
5194 if (!has_ascii_incompat)
5195 has_ascii_incompat = enc;
5196 else if (has_ascii_incompat != enc)
5197 rb_raise(rb_eArgError, "incompatible encodings: %s and %s",
5198 rb_enc_name(has_ascii_incompat), rb_enc_name(enc));
5199 }
5200 else if (rb_enc_str_asciionly_p(e)) {
5201 has_asciionly = 1;
5202 }
5203 else {
5204 if (!has_ascii_compat_fixed)
5205 has_ascii_compat_fixed = enc;
5206 else if (has_ascii_compat_fixed != enc)
5207 rb_raise(rb_eArgError, "incompatible encodings: %s and %s",
5208 rb_enc_name(has_ascii_compat_fixed), rb_enc_name(enc));
5209 }
5210 v = rb_reg_s_quote(Qnil, e);
5211 }
5212 if (has_ascii_incompat) {
5213 if (has_asciionly) {
5214 rb_raise(rb_eArgError, "ASCII incompatible encoding: %s",
5215 rb_enc_name(has_ascii_incompat));
5216 }
5217 if (has_ascii_compat_fixed) {
5218 rb_raise(rb_eArgError, "incompatible encodings: %s and %s",
5219 rb_enc_name(has_ascii_incompat), rb_enc_name(has_ascii_compat_fixed));
5220 }
5221 }
5222
5223 if (i == 0) {
5224 rb_enc_copy(source, v);
5225 }
5226 rb_str_append(source, v);
5227 }
5228
5229 if (has_ascii_incompat) {
5230 result_enc = has_ascii_incompat;
5231 }
5232 else if (has_ascii_compat_fixed) {
5233 result_enc = has_ascii_compat_fixed;
5234 }
5235 else {
5236 result_enc = rb_ascii8bit_encoding();
5237 }
5238
5239 rb_enc_associate(source, result_enc);
5240 return rb_class_new_instance(1, &source, rb_cRegexp);
5241 }
5242}
5243
5244/*
5245 * call-seq:
5246 * Regexp.union(*patterns) -> regexp
5247 * Regexp.union(array_of_patterns) -> regexp
5248 *
5249 * Returns a regexp that is the union of the given patterns:
5250 *
5251 * r = Regexp.union(%w[cat dog]) # => /cat|dog/
5252 * r.match('cat') # => #<MatchData "cat">
5253 * r.match('dog') # => #<MatchData "dog">
5254 * r.match('cog') # => nil
5255 *
5256 * Each string pattern is escaped so that it is matched literally:
5257 *
5258 * Regexp.union('penzance') # => /penzance/
5259 * Regexp.union('a+b*c') # => /a\+b\*c/
5260 * Regexp.union('skiing', 'sledding') # => /skiing|sledding/
5261 * Regexp.union(['skiing', 'sledding']) # => /skiing|sledding/
5262 *
5263 * For each pattern that is a regexp, it is used as is,
5264 * including its flags:
5265 *
5266 * Regexp.union(/foo/i, /bar/m, /baz/x)
5267 * # => /(?i-mx:foo)|(?m-ix:bar)|(?x-mi:baz)/
5268 * Regexp.union([/foo/i, /bar/m, /baz/x])
5269 * # => /(?i-mx:foo)|(?m-ix:bar)|(?x-mi:baz)/
5270 *
5271 * With no arguments, returns <tt>/(?!)/</tt>:
5272 *
5273 * Regexp.union # => /(?!)/
5274 *
5275 * If any regexp pattern contains captures, the behavior is unspecified.
5276 *
5277 */
5278static VALUE
5279rb_reg_s_union_m(VALUE self, VALUE args)
5280{
5281 VALUE v;
5282 if (RARRAY_LEN(args) == 1 &&
5283 !NIL_P(v = rb_check_array_type(rb_ary_entry(args, 0)))) {
5284 return rb_reg_s_union(self, v);
5285 }
5286 return rb_reg_s_union(self, args);
5287}
5288
5289/*
5290 * call-seq:
5291 * Regexp.linear_time?(re)
5292 * Regexp.linear_time?(string, options = 0)
5293 *
5294 * Returns +true+ if matching against <tt>re</tt> can be
5295 * done in linear time to the input string.
5296 *
5297 * Regexp.linear_time?(/re/) # => true
5298 *
5299 * Note that this is a property of the ruby interpreter, not of the argument
5300 * regular expression. Identical regexp can or cannot run in linear time
5301 * depending on your ruby binary. Neither forward nor backward compatibility
5302 * is guaranteed about the return value of this method. Our current algorithm
5303 * is (*1) but this is subject to change in the future. Alternative
5304 * implementations can also behave differently. They might always return
5305 * false for everything.
5306 *
5307 * (*1): https://doi.org/10.1109/SP40001.2021.00032
5308 *
5309 */
5310static VALUE
5311rb_reg_s_linear_time_p(int argc, VALUE *argv, VALUE self)
5312{
5313 struct reg_init_args args;
5314 VALUE re = reg_extract_args(argc, argv, &args);
5315
5316 if (NIL_P(re)) {
5317 re = reg_init_args(rb_reg_alloc(), args.str, args.enc, args.flags);
5318 }
5319
5320 return RBOOL(onig_check_linear_time(RREGEXP_PTR(re)));
5321}
5322
5323/* :nodoc: */
5324static VALUE
5325rb_reg_init_copy(VALUE copy, VALUE re)
5326{
5327 if (!OBJ_INIT_COPY(copy, re)) return copy;
5328 rb_reg_check(re);
5329 return reg_copy(copy, re);
5330}
5331
5332static VALUE
5333do_regsub(VALUE str, VALUE src, VALUE regexp, int num_regs, const OnigPosition *beg, const OnigPosition *end)
5334{
5335 VALUE val = 0;
5336 char *p, *s, *e;
5337 int no, clen;
5338 rb_encoding *str_enc = rb_enc_get(str);
5339 rb_encoding *src_enc = rb_enc_get(src);
5340 int acompat = rb_enc_asciicompat(str_enc);
5341 rb_len_t n;
5342#define ASCGET(s,e,cl) (acompat ? (*(cl)=1,ISASCII((s)[0])?(s)[0]:-1) : rb_enc_ascget((s), (e), (cl), str_enc))
5343
5344 RSTRING_GETMEM(str, s, n);
5345 p = s;
5346 e = s + n;
5347
5348 while (s < e) {
5349 int c = ASCGET(s, e, &clen);
5350 char *ss;
5351
5352 if (c == -1) {
5353 s += mbclen(s, e, str_enc);
5354 continue;
5355 }
5356 ss = s;
5357 s += clen;
5358
5359 if (c != '\\' || s == e) continue;
5360
5361 if (!val) {
5362 val = rb_str_buf_new(ss-p);
5363 }
5364 rb_enc_str_buf_cat(val, p, ss-p, str_enc);
5365
5366 c = ASCGET(s, e, &clen);
5367 if (c == -1) {
5368 s += mbclen(s, e, str_enc);
5369 rb_enc_str_buf_cat(val, ss, s-ss, str_enc);
5370 p = s;
5371 continue;
5372 }
5373 s += clen;
5374
5375 p = s;
5376 switch (c) {
5377 case '1': case '2': case '3': case '4':
5378 case '5': case '6': case '7': case '8': case '9':
5379 if (!NIL_P(regexp) && onig_noname_group_capture_is_active(RREGEXP_PTR(regexp))) {
5380 no = c - '0';
5381 }
5382 else {
5383 continue;
5384 }
5385 break;
5386
5387 case 'k':
5388 if (s < e && ASCGET(s, e, &clen) == '<') {
5389 char *name, *name_end;
5390
5391 name_end = name = s + clen;
5392 while (name_end < e) {
5393 c = ASCGET(name_end, e, &clen);
5394 if (c == '>') break;
5395 name_end += c == -1 ? mbclen(name_end, e, str_enc) : clen;
5396 }
5397 if (name_end < e) {
5398 VALUE n = rb_str_subseq(str, (rb_len_t)(name - RSTRING_PTR(str)),
5399 (rb_len_t)(name_end - name));
5400 struct re_registers tmp = {
5401 .allocated = num_regs,
5402 .num_regs = num_regs,
5403 .beg = (OnigPosition *)beg,
5404 .end = (OnigPosition *)end,
5405 };
5406 if ((no = NAME_TO_NUMBER(&tmp, regexp, n, name, name_end)) < 1) {
5407 name_to_backref_error(n);
5408 }
5409 p = s = name_end + clen;
5410 break;
5411 }
5412 else {
5413 rb_raise(rb_eRuntimeError, "invalid group name reference format");
5414 }
5415 }
5416
5417 rb_enc_str_buf_cat(val, ss, s-ss, str_enc);
5418 continue;
5419
5420 case '0':
5421 case '&':
5422 no = 0;
5423 break;
5424
5425 case '`':
5426 rb_enc_str_buf_cat(val, RSTRING_PTR(src), beg[0], src_enc);
5427 continue;
5428
5429 case '\'':
5430 rb_enc_str_buf_cat(val, RSTRING_PTR(src)+end[0], RSTRING_LEN(src)-end[0], src_enc);
5431 continue;
5432
5433 case '+':
5434 no = num_regs-1;
5435 while (beg[no] == -1 && no > 0) no--;
5436 if (no == 0) continue;
5437 break;
5438
5439 case '\\':
5440 rb_enc_str_buf_cat(val, s-clen, clen, str_enc);
5441 continue;
5442
5443 default:
5444 rb_enc_str_buf_cat(val, ss, s-ss, str_enc);
5445 continue;
5446 }
5447
5448 if (no >= 0) {
5449 if (no >= num_regs) continue;
5450 if (beg[no] == -1) continue;
5451 rb_enc_str_buf_cat(val, RSTRING_PTR(src)+beg[no], end[no]-beg[no], src_enc);
5452 }
5453 }
5454
5455 if (!val) return str;
5456 if (p < e) {
5457 rb_enc_str_buf_cat(val, p, e-p, str_enc);
5458 }
5459
5460 return val;
5461#undef ASCGET
5462}
5463
5464VALUE
5465rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
5466{
5467 return do_regsub(str, src, regexp, regs->num_regs, regs->beg, regs->end);
5468}
5469
5470VALUE
5471rb_reg_regsub_match(VALUE str, VALUE src, VALUE match)
5472{
5473 return do_regsub(str, src, RMATCH(match)->regexp,
5474 RMATCH_NREGS(match), RMATCH_BEG_PTR(match), RMATCH_END_PTR(match));
5475}
5476
5477static VALUE
5478ignorecase_getter(ID _x, VALUE *_y)
5479{
5480 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "variable $= is no longer effective");
5481 return Qfalse;
5482}
5483
5484static void
5485ignorecase_setter(VALUE val, ID id, VALUE *_)
5486{
5487 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "variable $= is no longer effective; ignored");
5488}
5489
5490static VALUE
5491match_getter(void)
5492{
5493 VALUE match = rb_backref_get();
5494
5495 if (NIL_P(match)) return Qnil;
5496 rb_match_busy(match);
5497 return match;
5498}
5499
5500static VALUE
5501get_LAST_MATCH_INFO(ID _x, VALUE *_y)
5502{
5503 return match_getter();
5504}
5505
5506static void
5507match_setter(VALUE val, ID _x, VALUE *_y)
5508{
5509 if (!NIL_P(val)) {
5510 Check_Type(val, T_MATCH);
5511 rb_match_busy(val);
5512 }
5513 rb_backref_set(val);
5514}
5515
5516/*
5517 * call-seq:
5518 * Regexp.last_match -> matchdata or nil
5519 * Regexp.last_match(n) -> string or nil
5520 * Regexp.last_match(name) -> string or nil
5521 *
5522 * With no argument, returns the value of <tt>$~</tt>,
5523 * which is the result of the most recent pattern match
5524 * (see {Regexp global variables}[rdoc-ref:Regexp@Global+Variables]):
5525 *
5526 * /c(.)t/ =~ 'cat' # => 0
5527 * Regexp.last_match # => #<MatchData "cat" 1:"a">
5528 * /a/ =~ 'foo' # => nil
5529 * Regexp.last_match # => nil
5530 *
5531 * With non-negative integer argument +n+, returns the _n_th field in the
5532 * matchdata, if any, or nil if none:
5533 *
5534 * /c(.)t/ =~ 'cat' # => 0
5535 * Regexp.last_match(0) # => "cat"
5536 * Regexp.last_match(1) # => "a"
5537 * Regexp.last_match(2) # => nil
5538 *
5539 * With negative integer argument +n+, counts backwards from the last field:
5540 *
5541 * Regexp.last_match(-1) # => "a"
5542 *
5543 * With string or symbol argument +name+,
5544 * returns the string value for the named capture, if any:
5545 *
5546 * /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ 'var = val'
5547 * Regexp.last_match # => #<MatchData "var = val" lhs:"var"rhs:"val">
5548 * Regexp.last_match(:lhs) # => "var"
5549 * Regexp.last_match('rhs') # => "val"
5550 * Regexp.last_match('foo') # Raises IndexError.
5551 *
5552 */
5553
5554static VALUE
5555rb_reg_s_last_match(int argc, VALUE *argv, VALUE _)
5556{
5557 if (rb_check_arity(argc, 0, 1) == 1) {
5558 VALUE match = rb_backref_get();
5559 int n;
5560 if (NIL_P(match)) return Qnil;
5561 n = match_backref_number(match, argv[0]);
5562 return rb_reg_nth_match(n, match);
5563 }
5564 return match_getter();
5565}
5566
5567static void
5568re_warn(const char *s)
5569{
5570 rb_warn("%s", s);
5571}
5572
5573// This function is periodically called during regexp matching
5574bool
5575rb_reg_timeout_p(regex_t *reg, void *end_time_)
5576{
5577 rb_hrtime_t *end_time = (rb_hrtime_t *)end_time_;
5578
5579 if (*end_time == 0) {
5580 // This is the first time to check interrupts;
5581 // just measure the current time and determine the end time
5582 // if timeout is set.
5583 rb_hrtime_t timelimit = reg->timelimit;
5584
5585 if (!timelimit) {
5586 // no per-object timeout.
5587 timelimit = rb_reg_match_time_limit;
5588 }
5589
5590 if (timelimit) {
5591 *end_time = rb_hrtime_add(timelimit, rb_hrtime_now());
5592 }
5593 else {
5594 // no timeout is set
5595 *end_time = RB_HRTIME_MAX;
5596 }
5597 }
5598 else {
5599 if (*end_time < rb_hrtime_now()) {
5600 // Timeout has exceeded
5601 return true;
5602 }
5603 }
5604
5605 return false;
5606}
5607
5608/*
5609 * call-seq:
5610 * Regexp.timeout -> float or nil
5611 *
5612 * It returns the current default timeout interval for Regexp matching in second.
5613 * +nil+ means no default timeout configuration.
5614 */
5615
5616static VALUE
5617rb_reg_s_timeout_get(VALUE dummy)
5618{
5619 double d = hrtime2double(rb_reg_match_time_limit);
5620 if (d == 0.0) return Qnil;
5621 return DBL2NUM(d);
5622}
5623
5624/*
5625 * call-seq:
5626 * Regexp.timeout = float or nil
5627 *
5628 * It sets the default timeout interval for Regexp matching in second.
5629 * +nil+ means no default timeout configuration.
5630 * This configuration is process-global. If you want to set timeout for
5631 * each Regexp, use +timeout+ keyword for <code>Regexp.new</code>.
5632 *
5633 * Regexp.timeout = 1
5634 * /^a*b?a*$/ =~ "a" * 100000 + "x" #=> regexp match timeout (RuntimeError)
5635 */
5636
5637static VALUE
5638rb_reg_s_timeout_set(VALUE dummy, VALUE timeout)
5639{
5640 rb_ractor_ensure_main_ractor("can not access Regexp.timeout from non-main Ractors");
5641
5642 set_timeout(&rb_reg_match_time_limit, timeout);
5643
5644 return timeout;
5645}
5646
5647/*
5648 * call-seq:
5649 * rxp.timeout -> float or nil
5650 *
5651 * It returns the timeout interval for Regexp matching in second.
5652 * +nil+ means no default timeout configuration.
5653 *
5654 * This configuration is per-object. The global configuration set by
5655 * Regexp.timeout= is ignored if per-object configuration is set.
5656 *
5657 * re = Regexp.new("^a*b?a*$", timeout: 1)
5658 * re.timeout #=> 1.0
5659 * re =~ "a" * 100000 + "x" #=> regexp match timeout (RuntimeError)
5660 */
5661
5662static VALUE
5663rb_reg_timeout_get(VALUE re)
5664{
5665 rb_reg_check(re);
5666 double d = hrtime2double(RREGEXP_PTR(re)->timelimit);
5667 if (d == 0.0) return Qnil;
5668 return DBL2NUM(d);
5669}
5670
5671/*
5672 * Document-class: RegexpError
5673 *
5674 * Raised when given an invalid regexp expression.
5675 *
5676 * Regexp.new("?")
5677 *
5678 * <em>raises the exception:</em>
5679 *
5680 * RegexpError: target of repeat operator is not specified: /?/
5681 */
5682
5683/*
5684 * Document-class: Regexp
5685 *
5686 * :include: doc/_regexp.rdoc
5687 */
5688
5689void
5690Init_Regexp(void)
5691{
5692 rb_eRegexpError = rb_define_class("RegexpError", rb_eStandardError);
5693
5694 onigenc_set_default_encoding(ONIG_ENCODING_ASCII);
5695 onig_set_warn_func(re_warn);
5696 onig_set_verb_warn_func(re_warn);
5697
5698 rb_define_virtual_variable("$~", get_LAST_MATCH_INFO, match_setter);
5699 rb_define_virtual_variable("$&", last_match_getter, 0);
5700 rb_define_virtual_variable("$`", prematch_getter, 0);
5701 rb_define_virtual_variable("$'", postmatch_getter, 0);
5702 rb_define_virtual_variable("$+", last_paren_match_getter, 0);
5703
5704 rb_gvar_ractor_local("$~");
5705 rb_gvar_ractor_local("$&");
5706 rb_gvar_ractor_local("$`");
5707 rb_gvar_ractor_local("$'");
5708 rb_gvar_ractor_local("$+");
5709 rb_gvar_box_dynamic("$~");
5710 rb_gvar_box_ready("$&");
5711 rb_gvar_box_ready("$`");
5712 rb_gvar_box_ready("$'");
5713 rb_gvar_box_ready("$+");
5714
5715 rb_define_virtual_variable("$=", ignorecase_getter, ignorecase_setter);
5716
5717 rb_cRegexp = rb_define_class("Regexp", rb_cObject);
5718 rb_define_alloc_func(rb_cRegexp, rb_reg_s_alloc);
5719 rb_define_singleton_method(rb_cRegexp, "compile", rb_class_new_instance_pass_kw, -1);
5720 rb_define_singleton_method(rb_cRegexp, "quote", rb_reg_s_quote, 1);
5721 rb_define_singleton_method(rb_cRegexp, "escape", rb_reg_s_quote, 1);
5722 rb_define_singleton_method(rb_cRegexp, "union", rb_reg_s_union_m, -2);
5723 rb_define_singleton_method(rb_cRegexp, "last_match", rb_reg_s_last_match, -1);
5724 rb_define_singleton_method(rb_cRegexp, "try_convert", rb_reg_s_try_convert, 1);
5725 rb_define_singleton_method(rb_cRegexp, "linear_time?", rb_reg_s_linear_time_p, -1);
5726
5727 rb_define_method(rb_cRegexp, "initialize", rb_reg_initialize_m, -1);
5728 rb_define_method(rb_cRegexp, "initialize_copy", rb_reg_init_copy, 1);
5729 rb_define_method(rb_cRegexp, "hash", rb_reg_hash, 0);
5730 rb_define_method(rb_cRegexp, "eql?", rb_reg_equal, 1);
5731 rb_define_method(rb_cRegexp, "==", rb_reg_equal, 1);
5732 rb_define_method(rb_cRegexp, "=~", rb_reg_match, 1);
5733 rb_define_method(rb_cRegexp, "===", rb_reg_eqq, 1);
5734 rb_define_method(rb_cRegexp, "~", rb_reg_match2, 0);
5735 rb_define_method(rb_cRegexp, "match", rb_reg_match_m, -1);
5736 rb_define_method(rb_cRegexp, "match?", rb_reg_match_m_p, -1);
5737 rb_define_method(rb_cRegexp, "to_s", rb_reg_to_s, 0);
5738 rb_define_method(rb_cRegexp, "inspect", rb_reg_inspect, 0);
5739 rb_define_method(rb_cRegexp, "source", rb_reg_source, 0);
5740 rb_define_method(rb_cRegexp, "casefold?", rb_reg_casefold_p, 0);
5741 rb_define_method(rb_cRegexp, "options", rb_reg_options_m, 0);
5742 rb_define_method(rb_cRegexp, "encoding", rb_obj_encoding, 0); /* in encoding.c */
5743 rb_define_method(rb_cRegexp, "fixed_encoding?", rb_reg_fixed_encoding_p, 0);
5744 rb_define_method(rb_cRegexp, "names", rb_reg_names, 0);
5745 rb_define_method(rb_cRegexp, "named_captures", rb_reg_named_captures, 0);
5746 rb_define_method(rb_cRegexp, "timeout", rb_reg_timeout_get, 0);
5747
5748 /* Raised when regexp matching timed out. */
5749 rb_eRegexpTimeoutError = rb_define_class_under(rb_cRegexp, "TimeoutError", rb_eRegexpError);
5750 rb_define_singleton_method(rb_cRegexp, "timeout", rb_reg_s_timeout_get, 0);
5751 rb_define_singleton_method(rb_cRegexp, "timeout=", rb_reg_s_timeout_set, 1);
5752
5753 /* see Regexp.options and Regexp.new */
5754 rb_define_const(rb_cRegexp, "IGNORECASE", INT2FIX(ONIG_OPTION_IGNORECASE));
5755 /* see Regexp.options and Regexp.new */
5756 rb_define_const(rb_cRegexp, "EXTENDED", INT2FIX(ONIG_OPTION_EXTEND));
5757 /* see Regexp.options and Regexp.new */
5758 rb_define_const(rb_cRegexp, "MULTILINE", INT2FIX(ONIG_OPTION_MULTILINE));
5759 /* see Regexp.options and Regexp.new */
5760 rb_define_const(rb_cRegexp, "FIXEDENCODING", INT2FIX(ARG_ENCODING_FIXED));
5761 /* see Regexp.options and Regexp.new */
5762 rb_define_const(rb_cRegexp, "NOENCODING", INT2FIX(ARG_ENCODING_NONE));
5763
5764 rb_global_variable(&reg_cache);
5765
5766 rb_cMatch = rb_define_class("MatchData", rb_cObject);
5767 rb_define_alloc_func(rb_cMatch, match_alloc);
5768 rb_undef_method(CLASS_OF(rb_cMatch), "new");
5769 rb_undef_method(CLASS_OF(rb_cMatch), "allocate");
5770
5771 rb_define_method(rb_cMatch, "initialize_copy", rb_match_init_copy, 1);
5772 rb_define_method(rb_cMatch, "regexp", match_regexp, 0);
5773 rb_define_method(rb_cMatch, "names", match_names, 0);
5774 rb_define_method(rb_cMatch, "size", match_size, 0);
5775 rb_define_method(rb_cMatch, "length", match_size, 0);
5776 rb_define_method(rb_cMatch, "offset", match_offset, 1);
5777 rb_define_method(rb_cMatch, "byteoffset", match_byteoffset, 1);
5778 rb_define_method(rb_cMatch, "bytebegin", match_bytebegin, 1);
5779 rb_define_method(rb_cMatch, "byteend", match_byteend, 1);
5780 rb_define_method(rb_cMatch, "begin", match_begin, 1);
5781 rb_define_method(rb_cMatch, "end", match_end, 1);
5782 rb_define_method(rb_cMatch, "match", match_nth, 1);
5783 rb_define_method(rb_cMatch, "match_length", match_nth_length, 1);
5784 rb_define_method(rb_cMatch, "to_a", match_to_a, 0);
5785 rb_define_method(rb_cMatch, "[]", match_aref, -1);
5786 rb_define_method(rb_cMatch, "captures", match_captures, 0);
5787 rb_define_alias(rb_cMatch, "deconstruct", "captures");
5788 rb_define_method(rb_cMatch, "named_captures", match_named_captures, -1);
5789 rb_define_method(rb_cMatch, "deconstruct_keys", match_deconstruct_keys, 1);
5790 rb_define_method(rb_cMatch, "values_at", match_values_at, -1);
5791 rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0);
5792 rb_define_method(rb_cMatch, "post_match", rb_reg_match_post, 0);
5793 rb_define_method(rb_cMatch, "to_s", match_to_s, 0);
5794 rb_define_method(rb_cMatch, "inspect", match_inspect, 0);
5795 rb_define_method(rb_cMatch, "string", match_string, 0);
5796 rb_define_method(rb_cMatch, "hash", match_hash, 0);
5797 rb_define_method(rb_cMatch, "eql?", match_equal, 1);
5798 rb_define_method(rb_cMatch, "==", match_equal, 1);
5799 rb_define_method(rb_cMatch, "integer_at", match_integer_at, -1);
5800}
Atomic operations.
#define RUBY_ATOMIC_PTR_LOAD(var)
Identical to RUBY_ATOMIC_LOAD, except it expects its arguments are void*.
Definition atomic.h:348
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval)
Identical to RUBY_ATOMIC_CAS, except it expects its arguments are void*.
Definition atomic.h:375
static bool rb_enc_isprint(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isprint(), except it additionally takes an encoding.
Definition ctype.h:180
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3350
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3139
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define FL_UNSET_RAW
Old name of RB_FL_UNSET_RAW.
Definition fl_type.h:130
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1707
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ISSPACE
Old name of rb_isspace.
Definition ctype.h:88
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:403
#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 INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define LEN2NUM
Old name of RB_LEN2NUM.
Definition len_t.h:33
#define rb_str_buf_new2
Old name of rb_str_buf_new_cstr.
Definition string.h:1704
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
Definition coderange.h:179
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:402
#define rb_str_new3
Old name of rb_str_new_shared.
Definition string.h:1701
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:128
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:125
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#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 NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#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:408
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define T_MATCH
Old name of RUBY_T_MATCH.
Definition value_type.h:69
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:127
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:129
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define scan_oct(s, l, e)
Old name of ruby_scan_oct.
Definition util.h:85
#define NUM2LEN
Old name of RB_NUM2LEN.
Definition len_t.h:34
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
Definition fl_type.h:126
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1702
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:409
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
VALUE rb_eRegexpError
RegexpError exception.
Definition re.c:70
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
Definition error.c:1464
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:464
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1459
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:103
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:654
VALUE rb_cMatch
MatchData class.
Definition re.c:1104
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:94
VALUE rb_cRegexp
Regexp class.
Definition re.c:3404
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:230
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
Encoding relates APIs.
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
Definition encoding.h:683
int rb_char_to_option_kcode(int c, int *option, int *kcode)
Converts a character option to its encoding.
Definition re.c:362
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:447
VALUE rb_enc_reg_new(const char *ptr, rb_len_t len, rb_encoding *enc, int opts)
Identical to rb_reg_new(), except it additionally takes an encoding.
Definition re.c:4215
rb_len_t rb_enc_strlen(const char *head, const char *tail, rb_encoding *enc)
Counts the number of characters of the passed string, according to the passed encoding.
Definition string.c:2403
rb_len_t rb_memsearch(const void *x, rb_len_t m, const void *y, rb_len_t n, rb_encoding *enc)
Looks for the passed string in the passed buffer.
Definition re.c:290
rb_len_t rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:853
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:3044
VALUE rb_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
void rb_ary_store(VALUE ary, rb_len_t key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_ary_resize(VALUE ary, rb_len_t len)
Expands or shrinks the passed array to the passed length.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
int rb_uv_to_utf8(char buf[6], unsigned long uv)
Encodes a Unicode codepoint into its UTF-8 representation.
Definition pack.c:1825
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
Definition vm.c:2130
void rb_backref_set(VALUE md)
Updates $~.
Definition vm.c:2136
VALUE rb_range_beg_len(VALUE range, rb_len_t *begp, rb_len_t *lenp, rb_len_t len, int err)
Deconstructs a numerical range.
Definition range.c:1949
int rb_reg_backref_number(VALUE match, VALUE backref)
Queries the index of the given named capture.
Definition re.c:1505
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:5089
VALUE rb_reg_last_match(VALUE md)
This just returns the argument, stringified.
Definition re.c:2516
void rb_match_busy(VALUE md)
Asserts that the given MatchData is "occupied".
Definition re.c:2019
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
Definition re.c:2492
VALUE rb_reg_match_post(VALUE md)
The portion of the original string after the given match.
Definition re.c:2574
VALUE rb_reg_nth_defined(int n, VALUE md)
Identical to rb_reg_nth_match(), except it just returns Boolean.
Definition re.c:2476
VALUE rb_reg_match_pre(VALUE md)
The portion of the original string before the given match.
Definition re.c:2542
VALUE rb_reg_new_str(VALUE src, int opts)
Identical to rb_reg_new(), except it takes the expression in Ruby's string instead of C's.
Definition re.c:4174
VALUE rb_reg_match_last(VALUE md)
The portion of the original string that captured at the very last.
Definition re.c:2603
VALUE rb_reg_new(const char *src, rb_len_t len, int opts)
Creates a new Regular expression.
Definition re.c:4229
VALUE rb_str_subseq(VALUE str, rb_len_t beg, rb_len_t len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
Definition string.c:3285
#define rb_hash_uint(h, i)
Just another name of st_hash_uint.
Definition string.h:967
#define rb_hash_end(h)
Just another name of st_hash_end.
Definition string.h:970
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:3935
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1706
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2050
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4293
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:3901
st_index_t rb_memhash(const void *ptr, rb_len_t len)
This is a universal hash function.
Definition random.c:1720
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4432
st_index_t rb_hash_start(st_index_t i)
Starts a series of hashing.
Definition random.c:1714
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:9188
VALUE rb_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
Definition string.c:1781
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:1091
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:397
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1155
int capa
Designed capacity of the buffer.
Definition io.h:11
int len
Length of the buffer.
Definition io.h:8
rb_len_t rb_reg_search(VALUE re, VALUE str, rb_len_t pos, int dir)
Runs the passed regular expression over the passed string.
Definition re.c:2421
regex_t * rb_reg_prepare_re(VALUE re, VALUE str)
Exercises various checks and preprocesses so that the given regular expression can be applied to the ...
Definition re.c:2264
OnigPosition rb_reg_onig_match(VALUE re, VALUE str, OnigPosition(*match)(regex_t *reg, VALUE str, struct re_registers *regs, void *args), void *args, struct re_registers *regs)
Runs a regular expression match using function match.
Definition re.c:2270
VALUE rb_reg_regcomp(VALUE str)
Creates a new instance of rb_cRegexp.
Definition re.c:4251
VALUE rb_reg_quote(VALUE str)
Escapes any characters that would have special meaning in a regular expression.
Definition re.c:4969
int rb_reg_region_copy(struct re_registers *dst, const struct re_registers *src)
Duplicates a match data.
Definition re.c:1135
rb_len_t rb_reg_adjust_startpos(VALUE re, VALUE str, rb_len_t pos, int dir)
Tell us if this is a wrong idea, but it seems this function has no usage at all.
Definition re.c:2298
unsigned long ruby_scan_hex(const char *str, size_t len, size_t *ret)
Interprets the passed string a hexadecimal unsigned integer.
Definition util.c:48
unsigned long ruby_scan_oct(const char *str, size_t len, size_t *consumed)
Interprets the passed string as an octal unsigned integer.
Definition util.c:39
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:375
#define ALLOCA_N(type, n)
Definition memory.h:295
#define RB_ALLOCV_N(type, v, n)
Allocates a memory region, possibly on stack.
Definition memory.h:339
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:363
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:170
#define RB_ALLOCV_END(v)
Polite way to declare that the given array is not used any longer.
Definition memory.h:352
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
#define RARRAY_AREF(a, i)
References an object in an array.
Definition rarray.h:421
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define RMATCH(obj)
Convenient casting macro.
Definition rmatch.h:37
#define RREGEXP(obj)
Convenient casting macro.
Definition rregexp.h:37
static struct re_pattern_buffer * RREGEXP_PTR(VALUE rexp)
Convenient getter function.
Definition rregexp.h:77
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:93
static rb_len_t RREGEXP_SRC_LEN(VALUE rexp)
Convenient getter function.
Definition rregexp.h:134
static char * RREGEXP_SRC_PTR(VALUE rexp)
Convenient getter function.
Definition rregexp.h:115
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#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
Ruby object's base components.
Definition rbasic.h:69
VALUE flags
Per-object flags.
Definition rbasic.h:81
Regular expression execution context.
Definition rmatch.h:79
VALUE regexp
The expression of this match.
Definition rmatch.h:92
union RMatch::@57 as
"Registers" of a match.
struct rmatch_offset * char_offset
Capture group offsets, in C array.
Definition rmatch.h:98
int char_offset_num_allocated
Number of rmatch_offset that ::rmatch::char_offset holds.
Definition rmatch.h:95
int num_regs
Number of capture-group registers.
Definition rmatch.h:101
int capa
Capacity of as.embed, in OnigPosition slots.
Definition rmatch.h:104
VALUE str
The target string that the match was made against.
Definition rmatch.h:87
Ruby's regular expression.
Definition rregexp.h:51
struct rb_regexp_variant * variants
Compiled variants for other encodings.
Definition rregexp.h:64
struct RBasic basic
Basic part, including flags and class.
Definition rregexp.h:54
const VALUE src
Source code of this expression.
Definition rregexp.h:57
Definition re.c:1260
Represents the region of a capture group.
Definition rmatch.h:65
rb_len_t end
End of a group.
Definition rmatch.h:67
rb_len_t beg
Beginning of a group.
Definition rmatch.h:66
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:142
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:425
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376