Merge strscan-3.0.7

This commit is contained in:
Hiroshi SHIBATA 2025-03-12 18:15:12 +09:00
parent 30379fa1e2
commit 64d93539e7
3 changed files with 107 additions and 63 deletions

View file

@ -3,6 +3,7 @@ require 'mkmf'
if RUBY_ENGINE == 'ruby'
$INCFLAGS << " -I$(top_srcdir)" if $extmk
have_func("onig_region_memsize", "ruby.h")
have_func("rb_reg_onig_match", "ruby.h")
create_makefile 'strscan'
else
File.write('Makefile', dummy_makefile("").join)

View file

@ -22,7 +22,7 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
#include <stdbool.h>
#define STRSCAN_VERSION "3.0.6"
#define STRSCAN_VERSION "3.0.7"
/* =======================================================================
Data Type Definitions
@ -539,6 +539,68 @@ adjust_register_position(struct strscanner *p, long position)
}
}
/* rb_reg_onig_match is available in Ruby 3.3 and later. */
#ifndef HAVE_RB_REG_ONIG_MATCH
static 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)
{
regex_t *reg = rb_reg_prepare_re(re, str);
bool tmpreg = reg != RREGEXP_PTR(re);
if (!tmpreg) RREGEXP(re)->usecnt++;
OnigPosition result = match(reg, str, regs, args);
if (!tmpreg) RREGEXP(re)->usecnt--;
if (tmpreg) {
if (RREGEXP(re)->usecnt) {
onig_free(reg);
}
else {
onig_free(RREGEXP_PTR(re));
RREGEXP_PTR(re) = reg;
}
}
if (result < 0) {
if (result != ONIG_MISMATCH) {
rb_raise(ScanError, "regexp buffer overflow");
}
}
return result;
}
#endif
static OnigPosition
strscan_match(regex_t *reg, VALUE str, struct re_registers *regs, void *args_ptr)
{
struct strscanner *p = (struct strscanner *)args_ptr;
return onig_match(reg,
match_target(p),
(UChar* )(CURPTR(p) + S_RESTLEN(p)),
(UChar* )CURPTR(p),
regs,
ONIG_OPTION_NONE);
}
static OnigPosition
strscan_search(regex_t *reg, VALUE str, struct re_registers *regs, void *args_ptr)
{
struct strscanner *p = (struct strscanner *)args_ptr;
return onig_search(reg,
match_target(p),
(UChar *)(CURPTR(p) + S_RESTLEN(p)),
(UChar *)CURPTR(p),
(UChar *)(CURPTR(p) + S_RESTLEN(p)),
regs,
ONIG_OPTION_NONE);
}
static VALUE
strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly)
{
@ -560,47 +622,14 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
}
if (RB_TYPE_P(pattern, T_REGEXP)) {
regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
regex_t *re;
long ret;
int tmpreg;
p->regex = pattern;
re = rb_reg_prepare_re(pattern, p->str);
tmpreg = re != RREGEXP_PTR(pattern);
if (!tmpreg) RREGEXP(pattern)->usecnt++;
OnigPosition ret = rb_reg_onig_match(pattern,
p->str,
headonly ? strscan_match : strscan_search,
(void *)p,
&(p->regs));
if (headonly) {
ret = onig_match(re,
match_target(p),
(UChar* )(CURPTR(p) + S_RESTLEN(p)),
(UChar* )CURPTR(p),
&(p->regs),
ONIG_OPTION_NONE);
}
else {
ret = onig_search(re,
match_target(p),
(UChar* )(CURPTR(p) + S_RESTLEN(p)),
(UChar* )CURPTR(p),
(UChar* )(CURPTR(p) + S_RESTLEN(p)),
&(p->regs),
ONIG_OPTION_NONE);
}
if (!tmpreg) RREGEXP(pattern)->usecnt--;
if (tmpreg) {
if (RREGEXP(pattern)->usecnt) {
onig_free(re);
}
else {
onig_free(RREGEXP_PTR(pattern));
RREGEXP_PTR(pattern) = re;
}
}
if (ret == -2) rb_raise(ScanError, "regexp buffer overflow");
if (ret < 0) {
/* not matched */
if (ret == ONIG_MISMATCH) {
return Qnil;
}
}
@ -1502,7 +1531,9 @@ strscan_named_captures(VALUE self)
named_captures_data data;
data.self = self;
data.captures = rb_hash_new();
onig_foreach_name(RREGEXP_PTR(p->regex), named_captures_iter, &data);
if (!RB_NIL_P(p->regex)) {
onig_foreach_name(RREGEXP_PTR(p->regex), named_captures_iter, &data);
}
return data.captures;
}

View file

@ -7,11 +7,7 @@
require 'strscan'
require 'test/unit'
class TestStringScanner < Test::Unit::TestCase
def create_string_scanner(string, *args)
StringScanner.new(string, *args)
end
module StringScannerTests
def test_s_new
s = create_string_scanner('test string')
assert_instance_of StringScanner, s
@ -155,8 +151,10 @@ class TestStringScanner < Test::Unit::TestCase
end
def test_string
s = create_string_scanner('test')
assert_equal 'test', s.string
s = create_string_scanner('test string')
assert_equal 'test string', s.string
s.scan(/test/)
assert_equal 'test string', s.string
s.string = 'a'
assert_equal 'a', s.string
s.scan(/a/)
@ -467,7 +465,10 @@ class TestStringScanner < Test::Unit::TestCase
assert_equal 'foo', s['a']
assert_equal 'bar', s['b']
assert_raise(IndexError) { s['c'] }
assert_raise_with_message(IndexError, /\u{30c6 30b9 30c8}/) { s["\u{30c6 30b9 30c8}"] }
# see https://github.com/jruby/jruby/issues/7644
unless RUBY_ENGINE == "jruby" && RbConfig::CONFIG['host_os'] =~ /mswin|win32|mingw/
assert_raise_with_message(IndexError, /\u{30c6 30b9 30c8}/) { s["\u{30c6 30b9 30c8}"] }
end
end
def test_pre_match
@ -751,19 +752,6 @@ class TestStringScanner < Test::Unit::TestCase
assert_nil(s.values_at(0, -1, 5, 2))
end
def test_fixed_anchor_true
assert_equal(true, StringScanner.new("a", fixed_anchor: true).fixed_anchor?)
end
def test_fixed_anchor_false
assert_equal(false, StringScanner.new("a").fixed_anchor?)
assert_equal(false, StringScanner.new("a", true).fixed_anchor?)
assert_equal(false, StringScanner.new("a", false).fixed_anchor?)
assert_equal(false, StringScanner.new("a", {}).fixed_anchor?)
assert_equal(false, StringScanner.new("a", fixed_anchor: nil).fixed_anchor?)
assert_equal(false, StringScanner.new("a", fixed_anchor: false).fixed_anchor?)
end
def test_scan_aref_repeatedly
s = StringScanner.new('test string')
assert_equal "test", s.scan(/\w(\w)(\w*)/)
@ -787,12 +775,36 @@ class TestStringScanner < Test::Unit::TestCase
def test_named_captures
omit("not implemented on TruffleRuby") if ["truffleruby"].include?(RUBY_ENGINE)
scan = StringScanner.new("foobarbaz")
assert_equal({}, scan.named_captures)
assert_equal(9, scan.match?(/(?<f>foo)(?<r>bar)(?<z>baz)/))
assert_equal({"f" => "foo", "r" => "bar", "z" => "baz"}, scan.named_captures)
end
end
class TestStringScannerFixedAnchor < TestStringScanner
class TestStringScanner < Test::Unit::TestCase
include StringScannerTests
def create_string_scanner(string, *args)
StringScanner.new(string, *args)
end
def test_fixed_anchor_true
assert_equal(true, StringScanner.new("a", fixed_anchor: true).fixed_anchor?)
end
def test_fixed_anchor_false
assert_equal(false, StringScanner.new("a").fixed_anchor?)
assert_equal(false, StringScanner.new("a", true).fixed_anchor?)
assert_equal(false, StringScanner.new("a", false).fixed_anchor?)
assert_equal(false, StringScanner.new("a", {}).fixed_anchor?)
assert_equal(false, StringScanner.new("a", fixed_anchor: nil).fixed_anchor?)
assert_equal(false, StringScanner.new("a", fixed_anchor: false).fixed_anchor?)
end
end
class TestStringScannerFixedAnchor < Test::Unit::TestCase
include StringScannerTests
def create_string_scanner(string, *args)
StringScanner.new(string, fixed_anchor: true)
end