SpiderMonkey でフィルタを書く

October 5th, 2006

最近の SpiderMonkey には readline() と print() があり、これを使って標準入力から読んで標準出力に書く、いわゆるフィルタ的なものを作ろうと思った。

var ln;
while (ln = readline()) {
    print(ln);
}

こんなので cat が出来そうな気がするけど

a

b

こういう空行まじりのファイルを食わせると、空行のところでループから抜けてしまう。なんでかといえば JavaScript では "" == false だから。

じゃあ readline() は EOF のときどうなるのか。こんなプログラムに

for (var i = 0; i < 10; i++) {
    var ln = readline();
    print(typeof ln + "\t'" + ln + "'");
}

さっきの3行のファイルを食わせてみると

string      'a'
string      ''
string      'b'
string      ''
string      ''
string      ''
string      ''
string      ''
string      ''
string      ''

EOF 区別できないよ……。しょうがないので SpiderMonkey の js.c に patch 書いた。

Index: js.c
===================================================================
RCS file: /cvsroot/mozilla/js/src/js.c,v
retrieving revision 3.125
diff -p -u -8 -r3.125 js.c
--- js.c    19 Sep 2006 06:48:25 -0000      3.125
+++ js.c    5 Oct 2006 08:48:22 -0000
@@ -639,17 +639,20 @@ ReadLine(JSContext *cx, JSObject *obj, u
         }

         bufsize *= 2;
         buf = tmp;
     }

     /* Treat the empty string specially. */
     if (buflength == 0) {
-        *rval = JS_GetEmptyStringValue(cx);
+        if (feof(from))
+            *rval = JSVAL_NULL;
+        else
+            *rval = JS_GetEmptyStringValue(cx);
         JS_free(cx, buf);
         return JS_TRUE;
     }

     /* Shrink the buffer to the real size. */
     tmp = JS_realloc(cx, buf, buflength);
     if (!tmp) {
         JS_free(cx, buf);

EOF で null を返すことにしたので、cat はこうなる。

var ln;
while ((ln = readline()) != null) {
    print(ln);
}

4 Responses to “SpiderMonkey でフィルタを書く”

  1. kou Says:

    このパッチは本体に取りこまれそうなのですか? 挙動が変わるとぎゃっと言う人がいるかもしれませんが...

  2. カトウ Says:

    まだ Bugzilla に投げてすらいない状況です。

  3. カトウ Says:

    Bugzilla に送ってみました。 「EOF が区別できないのが仕様」というのも結構ぎゃっとなると思うので、 できれば取りこまれると良いんですが。

  4. kou Says:

    であれば,is_eof()(isEof()?)みたいなのがあるとよいのかもしれませんね.