Skip to content

Instantly share code, notes, and snippets.

@rkh
Created April 28, 2013 14:13
Show Gist options
  • Select an option

  • Save rkh/5477001 to your computer and use it in GitHub Desktop.

Select an option

Save rkh/5477001 to your computer and use it in GitHub Desktop.
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index b81e1f1..2475ba5 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -38,6 +38,9 @@ struct strscanner
/* the regexp register; legal only when MATCHED_P(s) */
struct re_registers regs;
+
+ /* regexp used for last scan */
+ VALUE regex;
};
#define MATCHED_P(s) ((s)->flags & FLAG_MATCHED)
@@ -445,17 +448,36 @@ strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
{
regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
struct strscanner *p;
- regex_t *re;
+ regex_t *re, *oldre;
long ret;
- int tmpreg;
+ int tmpreg, oldtmpreg;
Check_Type(regex, T_REGEXP);
GET_SCANNER(self, p);
+ // THIS SEGFAULTS
+ // if (p->regex) {
+ // oldre = rb_reg_prepare_re(regex, p->str);
+ // oldtmpreg = oldre != RREGEXP(p->regex)->ptr;
+ // if (oldtmpreg) {
+ // if (RREGEXP(p->regex)->usecnt) {
+ // onig_free(oldre);
+ // }
+ // else {
+ // onig_free(RREGEXP(p->regex)->ptr);
+ // RREGEXP(p->regex)->ptr = oldre;
+ // }
+ // } else {
+ // RREGEXP(p->regex)->usecnt--;
+ // }
+ // }
+
CLEAR_MATCH_STATUS(p);
if (S_RESTLEN(p) < 0) {
return Qnil;
}
+
+ p->regex = regex;
re = rb_reg_prepare_re(regex, p->str);
tmpreg = re != RREGEXP(regex)->ptr;
if (!tmpreg) RREGEXP(regex)->usecnt++;
@@ -471,16 +493,6 @@ strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
(UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)),
&(p->regs), ONIG_OPTION_NONE);
}
- if (!tmpreg) RREGEXP(regex)->usecnt--;
- if (tmpreg) {
- if (RREGEXP(regex)->usecnt) {
- onig_free(re);
- }
- else {
- onig_free(RREGEXP(regex)->ptr);
- RREGEXP(regex)->ptr = re;
- }
- }
if (ret == -2) rb_raise(ScanError, "regexp buffer overflow");
if (ret < 0) {
@@ -976,11 +988,14 @@ strscan_matched_size(VALUE self)
* Return the n-th subgroup in the most recent match.
*
* s = StringScanner.new("Fri Dec 12 1975 14:39")
- * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 "
+ * s.scan(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /) # -> "Fri Dec 12 "
* s[0] # -> "Fri Dec 12 "
* s[1] # -> "Fri"
* s[2] # -> "Dec"
* s[3] # -> "12"
+ * s[:wday] # -> "Fri"
+ * s[:month] # -> "Dec"
+ * s[:day] # -> "12"
* s.post_match # -> "1975 14:39"
* s.pre_match # -> ""
*/
@@ -993,7 +1008,16 @@ strscan_aref(VALUE self, VALUE idx)
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
- i = NUM2LONG(idx);
+ if (TYPE(idx) == T_SYMBOL) {
+ const char *name, *name_end;
+ name = rb_id2name(SYM2ID(idx));
+ name_end = name + strlen(name);
+ i = onig_name_to_backref_number(RREGEXP(p->regex)->ptr,
+ (const unsigned char* )name, (const unsigned char* )name_end, &(p->regs));
+ } else {
+ i = NUM2LONG(idx);
+ }
+
if (i < 0)
i += p->regs.num_regs;
if (i < 0) return Qnil;
diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb
index 2c4cf90..c1c356e 100644
--- a/test/strscan/test_stringscanner.rb
+++ b/test/strscan/test_stringscanner.rb
@@ -457,6 +457,14 @@ class TestStringScanner < Test::Unit::TestCase
assert_equal true, s[2].tainted?
assert_equal true, s[3].tainted?
assert_equal true, s[4].tainted?
+
+ s = StringScanner.new("foo bar")
+ s.scan /(?<a>(\w+)) (?<b>(\w+))/
+ assert_equal 'foo', s[1]
+ assert_equal 'bar', s[2]
+ assert_equal 'foo', s[:a]
+ assert_equal 'bar', s[:b]
+ assert_equal nil, s[:c]
end
def test_pre_match
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment