summaryrefslogtreecommitdiff
path: root/sprintf.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-10-16 13:44:19 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-10-16 13:44:19 +0000
commit67f14c022b34df77a0cda498024a2f6195d91f40 (patch)
tree1c692bb3ac6318d962dcfe820d7f69bbcd7c4131 /sprintf.c
parentb879196e328f1d6c73a285ffd285cb4fc35a76f0 (diff)
* sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
unnumbered arguments. [ruby-dev:18531] get rid of memory leak at exception. [ruby-core:00460] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2961 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'sprintf.c')
-rw-r--r--sprintf.c45
1 files changed, 30 insertions, 15 deletions
diff --git a/sprintf.c b/sprintf.c
index e60db6f269..190af52e86 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -62,11 +62,13 @@ remove_sign_bits(str, base)
#define FWIDTH 32
#define FPREC 64
-#define CHECK(l) \
+#define CHECK(l) do {\
while (blen + (l) >= bsiz) {\
- REALLOC_N(buf, char, bsiz*2);\
bsiz*=2;\
- }
+ }\
+ rb_str_resize(result, bsiz);\
+ buf = RSTRING(result)->ptr;\
+} while (0)
#define PUSH(s, l) do { \
CHECK(l);\
@@ -74,8 +76,18 @@ remove_sign_bits(str, base)
blen += (l);\
} while (0)
-#define GETARG() \
- ((nextarg >= argc) ? (rb_raise(rb_eArgError, "too few argument."), 0) : argv[nextarg++])
+#define GETARG() (nextvalue != Qundef ? nextvalue : \
+ posarg < 0 ? \
+ (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \
+ (posarg = nextarg++, GETNTHARG(posarg)))
+
+#define GETPOSARG(n) (posarg > 0 ? \
+ (rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg), 0) : \
+ ((n < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", n), 0) : \
+ (posarg = -1, GETNTHARG(n))))
+
+#define GETNTHARG(nth) \
+ ((nth >= argc) ? (rb_raise(rb_eArgError, "too few argument."), 0) : argv[nth])
#define GETASTER(val) do { \
t = p++; \
@@ -87,10 +99,7 @@ remove_sign_bits(str, base)
rb_raise(rb_eArgError, "malformed format string - %%*[0-9]"); \
} \
if (*p == '$') { \
- int curarg = nextarg; \
- nextarg = n; \
- tmp = GETARG(); \
- nextarg = curarg; \
+ tmp = GETPOSARG(n); \
} \
else { \
tmp = GETARG(); \
@@ -110,19 +119,22 @@ rb_f_sprintf(argc, argv)
VALUE result;
int width, prec, flags = FNONE;
- int nextarg = 0;
+ int nextarg = 1;
+ int posarg = 0;
int tainted = 0;
+ VALUE nextvalue;
VALUE tmp;
VALUE str;
- fmt = GETARG();
+ fmt = GETNTHARG(0);
if (OBJ_TAINTED(fmt)) tainted = 1;
StringValue(fmt);
p = RSTRING(fmt)->ptr;
end = p + RSTRING(fmt)->len;
blen = 0;
bsiz = 120;
- buf = ALLOC_N(char, bsiz);
+ result = rb_str_buf_new(bsiz);
+ buf = RSTRING(result)->ptr;
for (; p < end; p++) {
char *t;
@@ -137,6 +149,7 @@ rb_f_sprintf(argc, argv)
p = t + 1; /* skip `%' */
width = prec = -1;
+ nextvalue = Qundef;
retry:
switch (*p) {
default:
@@ -181,7 +194,10 @@ rb_f_sprintf(argc, argv)
rb_raise(rb_eArgError, "malformed format string - %%[0-9]");
}
if (*p == '$') {
- nextarg = n;
+ if (nextvalue != Qundef) {
+ rb_raise(rb_eArgError, "value given twice - %d$", n);
+ }
+ nextvalue = GETPOSARG(n);
p++;
goto retry;
}
@@ -579,8 +595,7 @@ rb_f_sprintf(argc, argv)
rb_raise(rb_eArgError, "too many argument for format string");
}
#endif
- result = rb_str_new(buf, blen);
- free(buf);
+ rb_str_resize(result, blen);
if (tainted) OBJ_TAINT(result);
return result;