Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UTF-8化したKaoriYa版Vimで標準入力からUTF-8な文字列を読み込むと文字化けする #370

Closed
msmhrt opened this issue Apr 22, 2013 · 26 comments

Comments

@msmhrt
Copy link

msmhrt commented Apr 22, 2013

【発生環境】
Vim: KaoriYa版 7.3.905 (2013/04/21版)
OS: Windows 7 Starter 32bit版

【概要】

  • UTF-8化したKaoriYa版Vimで標準入力からUTF-8な文字列を読み込むと文字化けする。
  • UTF-8化していないKaoriYa版Vimであれば文字化けしない。
  • 同じ内容を標準入力ではなくファイルにして渡した場合も文字化けしない。

【再現手順】

  1. switches\catalog\utf-8.vimswitches\enabled\にコピーして、KaoriYa版VimをUTF-8化する
  2. UTF-8で "あ\r\n" (= "\xe3\x81\x82\r\n")という内容の5バイトのファイル、aを用意する
  3. vim aでファイルを開く → fileencodingutf-8になって "あ" と正しく表示される
  4. type a | vim -で標準入力から流し込む → fileencodingucs-2leになって "臣?" と化けて表示される
  5. switches\enabled\utf-8.vimを削除して、Vimを元に戻す
  6. type a | vim -で標準入力から流し込む → fileencodingutf-8になって "あ" と正しく表示される

【その他】
標準入力から流した時だけというのが解せなかったのですが、guessの既知の制限か何かだったらすみません。

@ghost ghost assigned koron Apr 22, 2013
@koron
Copy link
Member

koron commented Apr 22, 2013

たしかどこかのissueにて観測済みですが、
今まさに手元でファイルでguessは成功しているけどiconvに失敗、
みたいなちょっと変わった事象を観測中。

ただデバッグは遅れそう。

@k-takata
Copy link
Member

fencs に utf-8 がないのが原因ではないでしょうか。
encode_japan.vim の該当箇所です。

    " UTF-8環境向けにfileencodingsを設定する
    let value = s:enc_jisx. ','.s:enc_cp932. ','.s:enc_eucjp. ','.value

おそらく末尾かどこかに、. ','.s:enc_utf8が必要と思われます。

ちなみに自ビルドのguess無し版だと 3. で直接ファイルを開く場合でも文字化けしました。

@koron
Copy link
Member

koron commented Apr 23, 2013

fencs に utf-8 がないのが原因ではないでしょうか。

enc=utf-8 の場合は fencs に utf-8 が入ってるとマズイ/もしくはその必要はありません。
私の手元では guess は正しく cp932 と解釈しているけど、
そのまま cp932 で読み込むとiconv変換に失敗しているという感じです。

@koron
Copy link
Member

koron commented Apr 23, 2013

おっと。私の根拠のデータはちょっとズレてるね。申し訳ない。

でも enc=utf-8 なら fencsにutf-8 が不要なのは Vim の仕様です。
どのfencにもマッチしなかったらencで読むというのがありますので。

ただ別件ですが「だいたいなんにでもマッチしてしまう ucs2-le」がfencsに入ってる事のほうが問題かもしれません。

@k-takata
Copy link
Member

あー、ほんとだ。fencs に utf-8 付けてもだめでした。
fencs から ucs-2le と ucs-2 を削除して、utf-8 もない場合だと正常に開けました。

@k-takata
Copy link
Member

ucs-2le/be → utf-8 の変換だと、Windowsでは(?) iconvは使っていないですよね?
iconvを使わない場合の変換処理のどこかでエラーチェックが漏れている?

@koron
Copy link
Member

koron commented Apr 23, 2013

Windowsでは(?) iconvは使っていない

だからかも。何も考えずに数値変換だけするから、どんな入力でも変換できちゃって、
結果なんでもUCS-2LEになっちゃうとか。

@koron
Copy link
Member

koron commented Apr 23, 2013

僕の手元の正しく読み込めない cp932 ファイルには壊れた文字があった…

++enc= で指定すると読めるのは謎。変換エラー無視するアレになってるのかな…

@koron
Copy link
Member

koron commented Apr 23, 2013

x_guessed_fileencoding が設定されてないことからguessは機能していないっぽい。

@msmhrt
Copy link
Author

msmhrt commented Apr 23, 2013

だからかも。何も考えずに数値変換だけするから、どんな入力でも変換できちゃって、
結果なんでもUCS-2LEになっちゃうとか。

エンコーディングとして UCS-2LE を明示的に指定した場合は別として、自動判定するのであればファイルサイズが2の倍数かどうかぐらいはチェックすべきかもしれませんね。

@koron
Copy link
Member

koron commented Apr 23, 2013

:set fencs-=ucs-2
:set fencs-=ucs-2le

してからやるとセーフらしい。
ucs-2* から utf-8 の変換にまつわる独自変換のコードがコケると、
そこで変換失敗して「UTF-8で変換なし」が機能しない、ということになりそう。

@msmhrt
Copy link
Author

msmhrt commented Apr 23, 2013

ucs-2* から utf-8 の変換にまつわる独自変換のコードがコケると、
そこで変換失敗して「UTF-8で変換なし」が機能しない、ということになりそう。

標準入力から流し込まずにファイルで指定すれば化けないという発生条件についても、それで説明がつくのでしょうか?
ちなみに標準入力から流し込んだ場合もファイルで指定した場合も、fileencodingsの値は、

fileencodings=guess,iso-2022-jp-3,cp932,euc-jisx0213,euc-jp,ucs-bom,ucs-2le,ucs-2

で同じでした。

@koron
Copy link
Member

koron commented Apr 23, 2013

標準入力から流し込まずにファイルで指定すれば化けないという発生条件についても、それで説明がつくのでしょうか?

ファイルの場合は guess が働き、標準入力の場合は働かないのだろうと推測しています。
それはすでに以下のように書いたとおりです。

x_guessed_fileencoding が設定されてないことからguessは機能していないっぽい。

@msmhrt
Copy link
Author

msmhrt commented Apr 23, 2013

ファイルの場合は guess が働き、標準入力の場合は働かないのだろうと推測しています。
それはすでに以下のように書いたとおりです。

x_guessed_fileencoding が設定されてないことからguessは機能していないっぽい。

あ、そういう事だったんですね。了解しました。

@koron
Copy link
Member

koron commented Apr 23, 2013

いまわかってることをざっくり書いときます。guessは切った状態で試してます。

  • enc=utf-8 時のfencs 内の ucs-2le がガン
  • ファイルが奇数バイトの場合は 変換エラー になりそこでfencsの試行が止まる(止まる詳細な経緯は未調査)
  • ファイルが偶数バイトの場合はエラーにならず ucs-2le として無理やりコンバートされる

以下、ポイントになりそうなところを抜粋

fileio.c:1797

/* Check for a trailing byte */
p = ptr + (size & ~1);
if (size & 1)
    tail = p;

fileio.c:1828

/* If there is a trailing incomplete sequence move it to
 * conv_rest[]. */
if (tail != NULL)
{
    conv_restlen = (int)((ptr + size) - tail);
    mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
    size -= conv_restlen;
}

奇数の場合だけ考えるなら、この先で変換に失敗した場合の扱いに問題がありそう。
偶数の場合を救うには verifyenc.vim みたいな仕組みが要りそう。

@koron
Copy link
Member

koron commented Apr 23, 2013

ucs-2le, ucs-2 は fencs から外す、っていうのでも良いかもしれない。

@koron
Copy link
Member

koron commented Apr 23, 2013

奇数の場合はコレで対処できた。
ただ stdin だと can_retry == false なのでどのみち正しく動かせなさそうではある。

diff -r ef341d8811b2 src/fileio.c
--- a/src/fileio.c  Mon Apr 15 22:22:58 2013 +0200
+++ b/src/fileio.c  Tue Apr 23 22:13:07 2013 +0900
@@ -1380,6 +1380,8 @@
 # endif
               )
            {
+               if (can_retry)
+               goto rewind_retry;
                if (conv_error == 0)
                conv_error = curbuf->b_ml.ml_line_count
                                - linecnt + 1;

@mattn
Copy link
Member

mattn commented Apr 23, 2013

stdinはseekableじゃないですからね

@koron
Copy link
Member

koron commented Apr 23, 2013

enc=utf-8 で utf-8 なファイルを読む時のロジックは一工夫したほうが良いかも。

というのは utf-8 は制約が強いからコンバートしないまでも valid かどうかの判定は可能。
それに対して ucs-2 系は偶数バイトである以外の制約がない。
だから ucs-2 系を先に判定しちゃうと utf-8 には回らなくなっちゃう。

@koron
Copy link
Member

koron commented Apr 23, 2013

とりあえず直近の対策として enc=utf-8 のときは fencs に ucs-2 及び ucs-2le を入れないようにする。

少し遠い対策としては

  • utf-8 は ucs-2 よりも(内部のTO UTF8なコンバータが稼働するよりも)先にトライする
  • その際 utf-8 として valid かどうか確認する

をすれば良さそう。

@k-takata
Copy link
Member

:set fencs-=ucs-2
:set fencs-=ucs-2le
してからやるとセーフらしい。

と同じことは上に書いてたつもりでした。
それはさておき、BOM無しの ucs-2 系を扱いたいという要望はどの程度あるんでしょうかね。
MS系のツールがはき出すファイルは必ずと言っていいほどBOMがついてますし。

@koron
Copy link
Member

koron commented Apr 23, 2013

と同じことは上に書いてたつもりでした。

ごめーんw 下の動作を追っててそこに至ったので。

BOM無しの ucs-2 系を扱いたいという要望はどの程度あるんでしょうかね。

とりあえず無視して良いんじゃないですかね。

直近の対策として enc=utf-8 のときは fencs に ucs-2 及び ucs-2le を入れないようにする。

本 issue としてはコレだけやれば良いかなと。

残りの作業は #371 でやりましょう。

@koron
Copy link
Member

koron commented Apr 23, 2013

修正しました。

https://bitbucket.org/koron/vim-kaoriya/commits/34e86f5c18722d12e22e3da6f3dec56c26c65f35

次回のリリースに反映されます。

@koron koron closed this as completed Apr 23, 2013
@k-takata
Copy link
Member

リンクを載せておきます。
https://groups.google.com/d/topic/vim_dev/wYDYDAYwlAY/discussion

@koron
Copy link
Member

koron commented Apr 23, 2013

ucs-2 は古いから代わりに utf-16 使えよって言われた。
Windows で使って問題ないだろうか?

@k-takata
Copy link
Member

奇数の場合はコレで対処できた。

7.3.915 で取り込まれました。
https://groups.google.com/d/topic/vim_dev/YmcGagsR704/discussion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants