uri decode 動いた - Scheme VM を書く

入力は UTF-8 前提ですが uri decode が動きました。
コードが不完全なのはあとで直すとしてとにかくうれしい。


なぜうれしいかというと R5RS の範囲では uri decode を書くのは、無理なのだけど R6RS では書けるから。
BinaryInputPort, TextualInputPort, Transcoder, Codec, CustomPort など実装が大変だった><。
あとで RFC を見てちゃんと書き直そう。

(print (decode "2%e3%81%a1%e3%82%83%e3%82%93%e3%81%ad%e3%82%8b"))
=> 2ちゃんねる

(define (decode s)
  (call-with-string-io
   s
   (lambda (in out)
     (let1 p (transcoded-port
              (make-custom-binary-input-port
               "cgi decode"
               (lambda (bv start count)
                 (let1 read-byte (lambda ()
                                   (let1 c (read-char in)
                                     (cond
                                      [(eof-object? c) (eof-object)]
                                      [(eq? #\+ c) 20]
                                      [(eq? #\% c)
                                       (let ([a (digit->integer (read-char in) 16)]
                                             [b (digit->integer (read-char in) 16)])
                                         (+ (* a 16) b))]
                                      [else
                                       (char->integer c)])))
                   (let loop ([size 0]
                              [b (read-byte)])
                     (cond
                      [(eof-object? b) size]
                      [else
                       (bytevector-u8-set! bv (+ start size) b)
                       (if (>= (+ size 1) count)
                           '()
                           (loop (+ size 1) (read-byte)))]))))
               #f #f #f)
              (make-transcoder (utf-8-codec)))
       (let loop ([c (read-char p)])
         (cond
          [(eof-object? c) '()]
          [else
           (display c out)
           (loop (read-char p))]))))))