From 48379c7309a0603186f6a450f73ea2178185589a Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 27 Mar 2009 23:49:52 +0000 Subject: [PATCH] * sprintf.c (rb_str_format): checks if named argument given twice. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23090 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 4 +++- sprintf.c | 20 ++++++++++++++------ test/ruby/test_sprintf.rb | 6 ++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index e63fa6dd18..8a6487cfd0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ -Sat Mar 28 06:18:27 2009 Nobuyoshi Nakada +Sat Mar 28 08:49:47 2009 Nobuyoshi Nakada + + * sprintf.c (rb_str_format): checks if named argument given twice. * sprintf.c (GETNAMEARG): remembers named arg is used, to get rid of too many arguments warning. diff --git a/sprintf.c b/sprintf.c index 81911703fd..9f3183a0ee 100644 --- a/sprintf.c +++ b/sprintf.c @@ -119,11 +119,12 @@ sign_bits(int base, const char *p) #define GETNTHARG(nth) \ ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[nth]) -#define GETNAMEARG(id) (posarg > 0 ? \ - (rb_raise(rb_eArgError, "named after unnumbered(%d)", posarg), 0) : \ +#define GETNAMEARG(id, name, len) ( \ + posarg > 0 ? \ + (rb_raise(rb_eArgError, "named%.*s after unnumbered(%d)", (len), (name), posarg), 0) : \ posarg == -1 ? \ - (rb_raise(rb_eArgError, "named after numbered"), 0) : \ - (posarg = -2, rb_hash_lookup(get_hash(&hash, argc, argv), id))) + (rb_raise(rb_eArgError, "named%.*s after numbered", (len), (name)), 0) : \ + (posarg = -2, rb_hash_lookup2(get_hash(&hash, argc, argv), id, Qundef))) #define GETNUM(n, val) \ for (; p < end && rb_enc_isdigit(*p, enc); p++) { \ @@ -472,6 +473,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) for (; p < end; p++) { const char *t; int n; + ID id = 0; for (t = p; t < end && *t != '%'; t++) ; PUSH(p, t - p); @@ -544,7 +546,6 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) { const char *start = p; char term = (*p == '<') ? '>' : '}'; - ID id; for (; p < end && *p != term; ) { p += rb_enc_mbclen(p, end, enc); @@ -552,8 +553,15 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) if (p >= end) { rb_raise(rb_eArgError, "malformed name - unmatched parenthesis"); } + if (id) { + rb_raise(rb_eArgError, "name%.*s after <%s>", + (int)(p - start + 1), start, rb_id2name(id)); + } id = rb_intern3(start + 1, p - start - 1, enc); - nextvalue = GETNAMEARG(ID2SYM(id)); + nextvalue = GETNAMEARG(ID2SYM(id), start, (int)(p - start + 1)); + if (nextvalue == Qundef) { + rb_raise(rb_eKeyError, "key%.*s not found", (int)(p - start + 1), start); + } if (term == '}') goto format_s; p++; goto retry; diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb index c2669a7131..15424d98ac 100644 --- a/test/ruby/test_sprintf.rb +++ b/test/ruby/test_sprintf.rb @@ -273,4 +273,10 @@ class TestSprintf < Test::Unit::TestCase b2 = (/\.\./ =~ s2) != nil assert(b1 == b2, "[ruby-dev:33224]") end + + def test_named + assert_equal("value", sprintf("%s", :key => "value")) + assert_raise(ArgumentError) {sprintf("%1$s", :key => "value")} + assert_raise(ArgumentError) {sprintf("%s", :key => "value")} + end end