iconv install memo

ceanではなぜかiconv-1.0/priv以下がインストールされないのでjungerlから手動でインストールした時のメモ。
参考 [ubuntu-jp] stack_chk_fail_local

普通にインストールした場合、"undefined symbol: __stack_chk_fail_local"というエラーで動かないので、jungerl/support/include.mkのLD_SHAREDの値を"ld -shared"から"gcc -shared"に変更する必要がある。

cvs -z3 -d:pserver:anonymous@jungerl.cvs.sourceforge.net:/cvsroot/jungerl co -P jungerl
cd jungerl
make conf
vi jungerl/support # ここでLD_SHAREDの値を変更
cd lib/iconv
make release
cd ..
cp iconv/release/iconv-1.0.tar.gz .
tar zxvf iconv-1.0.tar.gz
cd iconv-1.0
make
cd ..
mv iconv-1.0 erlangのebinのディレクトリ

動作確認。

% erl
> lists:filter(fun(Elem) -> 0 /= string:str(Elem,"iconv") end,code:get_path()).
["/home/troter/opt/erlang/r11b-4/lib/erlang/lib/iconv-1.0/ebin"]
> iconv:start().
{ok,<0.33.0>}
> {ok, Cb} = iconv:open("UTF8", "Shift_JIS").
{ok,<<136,5,29,8>>}
> {ok, {_,_,Body}} = http:request("http://www.google.com").

=INFO REPORT==== 13-May-2007::19:00:12 ===
The inets application was not started. Has now been started as a temporary application.
{ok,{{"HTTP/1.1",200,"OK"},
     [{"cache-control","private"},
      {"date","Sun, 13 May 2007 10:00:12 GMT"},
      {"server","GWS/2.1"},
      {"content-length","2844"},
      {"content-type","text/html; charset=Shift_JIS"},
      {"set-cookie",
       "PREF=ID=a40fc2c4b72033e1:TM=1179050412:LM=1179050412:S=OEy5K_fGRGI3ZHc4; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.co.jp"}],
     [60,
      104,
      116,
      109,
      108,
      62,
      60,
      104,
      101,
      97,
      100,
      62,
      60,
      109,
      101,
      116,
      97,
      32,
      104,
      116,
      116,
      112,
      45,
      101|...]}}
> iconv:conv(Cb, Body).
{error,e2big}

なんか動かなかった。バッファが足りないって。

  • iconv_drv.c 抜粋
   22 /* convert buffers */
   23 #define INBUF_SZ 512
   24 #define OUTBUF_SZ INBUF_SZ*4
   25 static char inbuf[INBUF_SZ];
   26 static char outbuf[OUTBUF_SZ];

  198 static void iv_conv(t_iconvdrv *iv, iconv_t cd, char *ip, int ileft)
  199 {
  200     int oleft=OUTBUF_SZ;
  201     char *op;
  202     int len;
  203     ErlDrvBinary *bin;
  204 
  205     op = &outbuf[0];
  206 
  207     /* Reset cd to initial state */
  208     iconv(cd, NULL, NULL, NULL, NULL);
  209 
  210     if (iconv(cd, &ip, &ileft, &op, &oleft) == (size_t) -1) {
  211 	if (errno == EILSEQ)
  212 	    driver_send_error(iv, &am_eilseq);
  213 	else if (errno == EINVAL)
  214 	    driver_send_error(iv, &am_einval);
  215 	else if (errno == E2BIG)
  216 	    driver_send_error(iv, &am_e2big);
  217 	else
  218 	    driver_send_error(iv, &am_unknown);
  219     }

2KB以上のファイルを入れたら動作しないらしいorz。

で、結局

letter: はてなから移行を元にして動くようにした。iconvの引数の意味がわからなくて、かなり戸惑った。

static void iv_conv(t_iconvdrv *iv, iconv_t cd, char *ip, int ileft)
{
    char *op;
    int oleft;
    ErlDrvBinary *bin;
    int out_size = 0;

    if (!(bin = driver_alloc_binary(OUTBUF_SZ))) {
        iconv_close(cd);
        driver_send_error(iv, &am_enomem);
    }
    op = bin->orig_bytes;
    oleft=OUTBUF_SZ;
    /* Reset cd to initial state */
    iconv(cd, NULL, NULL, NULL, NULL);

    while(1) {
        if (iconv(cd, &ip, &ileft, &op, &oleft) == (size_t) -1) {
            if (errno == E2BIG) {
                out_size += OUTBUF_SZ - oleft;
                if (!(bin = driver_realloc_binary(bin, out_size + OUTBUF_SZ))) {
                    iconv_close(cd);
                    driver_send_error(iv, &am_enomem);
                }
                op = bin->orig_bytes + out_size;
                oleft = OUTBUF_SZ;
                continue;
            }
            else if (errno == EINVAL)
                driver_send_error(iv, &am_einval);
            else if (errno == EILSEQ)
                driver_send_error(iv, &am_eilseq);
            else
                driver_send_error(iv, &am_unknown);
        }
        out_size += OUTBUF_SZ - oleft;
        break;
    }
    driver_send_bin(iv, bin, out_size);
    driver_free_binary(bin);

    return;
}