Clinkの日本語パス問題を修正(2)

前回の続き。
カレントディレクトリのパスに日本語が含まれていても入力行の改行位置が狂わないようにするには、wcwidth(x)マクロをきちんと文字幅を返すように実装すればよいのですが、このマクロの引数"x"はwchar_tの文字です。
そしてwchar_t=UNICODE(UTF-16)には「文字幅」という概念がありません。所謂「全角」「半角」などという「幅の違い」は「文字の違い」ではないというのがUNICODEの基本原則なので。
(正確には互換性のために「East_Asian_Width特性」がありますが)

なので、文字幅を求めるために一旦ShiftJIS(CP932)に変換して、そのバイト数を求めるというロジックを実装することにします。

int hooked_wcwidth(wchar_t wc)
{
    int width; 

    width = WideCharToMultiByte(
        CP_ACP, 0,
        &wc, 1,
        NULL, 0,
        NULL, NULL
    );

    return width;
}

WideCharToMultiByteはワイド文字列をマルチバイト文字列に変換するWin32APIですが、これの第6パラメータに0を指定すると変換は行われず単に変換に必要なバッファのバイト数を返します。
今回はこのバイト数が求める文字幅そのものですから、変換バッファ(第5パラメータ)を確保せずにNULL, 0,で呼び出せばおしまいです。

あとは、少しでも高速化するためにwcが英数字(U+0000〜U+007F)だったら計算するまでもなくその時点で"1"を返す、という風にマクロを書き直します。

#define wcwidth(x)          (((x) > 0x7f) ? hooked_wcwidth(x) : 1)

Windows7上では以上でOKで「めでたしめでたし」と思っていたのですが、Windows XPで動かしたらまだ不具合が…
というわけで次回に続きます。