[#7631] 1.3 to 1.4 — Katsuyuki Komatsu <komatsu@...>

小松です。

26 messages 1999/08/12
[#7632] Re: 1.3 to 1.4 — matz@... (Yukihiro Matsumoto) 1999/08/12

まつもと ゆきひろです

[#7634] Re: 1.3 to 1.4 — Katsuyuki Komatsu <komatsu@...> 1999/08/13

小松です。

[#7636] Re: 1.3 to 1.4 — matz@... (Yukihiro Matsumoto) 1999/08/13

まつもと ゆきひろです

[#7638] cvs HEAD (Re: Re: 1.3 to 1.4) — EGUCHI Osamu <eguchi@...> 1999/08/13

えぐち@エスアンドイーです。

[#7647] Re: cvs HEAD (Re: Re: 1.3 to 1.4) — matz@... (Yukihiro Matsumoto) 1999/08/13

まつもと ゆきひろです

[#7641] Re: [ruby-ext:00382] New coerce scheme — keiju@... (石塚圭樹)

けいじゅ@日本ラショナルソフトウェアです.

26 messages 1999/08/13

[ruby-dev:7754] Re: [ruby-list:16313] Re: printf の $ について

From: Yasuhiro Fukuma <yasuf@...>
Date: 1999-08-25 15:07:02 UTC
List: ruby-dev #7754
福間@福岡 です。

元ネタは [ruby-list:16302] から始まるスレッドです。

記事 <E11JWxT-0004km-00@ev.netlab.co.jp> にて、
matz@netlab.co.jp (Yukihiro Matsumoto) さんは書きました:

> もっともRubyのprintfって実際にはprintfそのままではないんで、
> スルーしてくれないから、$nが使えるプラットフォームでも対応で
> きないんですが、このRubyのprintf自身が$nに対応することそのも
> のは面倒であっても不可能ではないですね。
> 
> sprintf.cのGETARG()マクロとかを書き換えればできるのかなあ。
> しかし、当面私自身が手を付ける気は無いですね。
> 誰かやる?

ということでやってみました。
ほとんどFreeBSDのlibcの真似っこですが、引数リストが単なる VALUE の配列
なので、va_arg() を駆使しなければならない本物の printf(3) family に
比べれば随分楽でした。

  irb(main):001:0> sprintf("%s:%s", "foo", "bar")
  "foo:bar"
  irb(main):002:0> sprintf("%2$s:%1$s", "foo", "bar")
  "bar:foo"
  irb(main):003:0> sprintf("%*2$s", "foo", 5)        
  "  foo"
  irb(main):004:0> sprintf("%.*2$s", "bar", 2)
  "ba"
  irb(main):005:0> sprintf("%*4$1$s:%.*s", "foo", 1, "bar", -4)
  "foo :b"

あまりテストしていませんが、たぶん大丈夫だと思います。

# 大丈夫じゃないかなぁ。

# まちょっと覚悟は…

ただし、sprintf("%d", 1, 2) などに対するチェックは、面倒なのでとりあえず
無効化してしまいました。

  a) n$ が一度も使われていないときはチェックしてあげる。
  b) 真面目にフラグなどを立ててチェックする。

などの方法があるにはありますが…。

---
 Yasuhiro Fukuma (福間 康弘) as Yasu.F @ Kitakyushu.Fukuoka.Japan
 Web site: http://www8.big.or.jp/~yasuf/
 PGP fingerprint = 17 25 8A F3 99 E5 7E 19  C0 EA 6E 03 8A C3 CE F0
 “今月の目標: 「盗聴に注意しましょう」”

Attachments (1)

sprintf.c.diff (2.52 KB, text/x-diff)
Index: sprintf.c
===================================================================
RCS file: /usr/local/cvs/Imported/netlab/ruby/sprintf.c,v
retrieving revision 1.2
diff -u -r1.2 sprintf.c
--- sprintf.c	1999/08/13 05:45:14	1.2
+++ sprintf.c	1999/08/25 10:33:39
@@ -136,8 +136,30 @@
 }
 
 #define GETARG() \
-    ((argc == 0)?(rb_raise(rb_eArgError, "too few argument."),0):(argc--,((argv++)[0])))
+    ((nextarg >= argc) ? (rb_raise(rb_eArgError, "too few argument."), 0) : argv[nextarg++])
 
+#define GETASTER(val) { \
+    t = p++; \
+    n = 0; \
+    for (; p < end && ISDIGIT(*p); p++) { \
+	n = 10 * n + (*p - '0'); \
+    } \
+    if (p >= end) { \
+	rb_raise(rb_eArgError, "malformed format string - %%*[0-9]"); \
+    } \
+    if (*p == '$') { \
+	int curarg = nextarg; \
+	nextarg = n; \
+	tmp = GETARG(); \
+	nextarg = curarg; \
+    } \
+    else { \
+	tmp = GETARG(); \
+	p = t; \
+    } \
+    val = NUM2INT(tmp); \
+}
+
 VALUE
 rb_f_sprintf(argc, argv)
     int argc;
@@ -149,6 +171,7 @@
     VALUE result;
 
     int width, prec, flags = FNONE;
+    int nextarg = 0;
     VALUE tmp;
     VALUE str;
 
@@ -161,6 +184,7 @@
 
     for (; p < end; p++) {
 	char *t;
+	int n;
 
 	for (t = p; t < end && *t != '%'; t++) ;
 	CHECK(t - p);
@@ -208,14 +232,20 @@
 
 	  case '1': case '2': case '3': case '4':
 	  case '5': case '6': case '7': case '8': case '9':
-	    flags |= FWIDTH;
-	    width = 0;
+	    n = 0;
 	    for (; p < end && ISDIGIT(*p); p++) {
-		width = 10 * width + (*p - '0');
+		n = 10 * n + (*p - '0');
 	    }
 	    if (p >= end) {
 		rb_raise(rb_eArgError, "malformed format string - %%[0-9]");
 	    }
+	    if (*p == '$') {
+		nextarg = n;
+		p++;
+		goto retry;
+	    }
+	    width = n;
+	    flags |= FWIDTH;
 	    goto retry;
 
 	  case '*':
@@ -224,8 +254,7 @@
 	    }
 
 	    flags |= FWIDTH;
-	    tmp = GETARG();
-	    width = NUM2INT(tmp);
+	    GETASTER(width);
 	    if (width < 0) {
 		flags |= FMINUS;
 		width = -width;
@@ -241,8 +270,7 @@
 	    prec = 0;
 	    p++;
 	    if (*p == '*') {
-		tmp = GETARG();
-		prec = NUM2INT(tmp);
+		GETASTER(prec);
 		if (prec > 0)
 		    flags |= FPREC;
 		p++;
@@ -609,9 +637,14 @@
     }
 
   sprint_exit:
-    if (RTEST(ruby_verbose) && argc > 0) {
+#if 0
+    /* XXX - We cannot validiate the number of arguments because
+     *       the format string may contain `n$'-style argument selector.
+     */
+    if (RTEST(ruby_verbose) && nextarg < argc) {
 	rb_raise(rb_eArgError, "too many argument for format string");
     }
+#endif
     result = rb_str_new(buf, blen);
     free(buf);
 

In This Thread

Prev Next