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