...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

Windowsのファイル名一覧

D言語とマルチバイト文字(MBS)は相性が悪いようで,特に Windows のファイル名一覧を取得して画面に出力しようとすると難しいことになっていた.
というか,今まで頑張ってもできなかった・・・なんだけど.
某やねう氏の D 用 BBS に埋もれてしまいそうなありがたいコードがあったので,ここで浮上させておくことにしよう.
参考→ http://yaneu.com/cgi/yanebbs/dobbsr.cgi?a=view&topic_id=1069952491&res_id=1092


// chopfname.d
import std.utf;
import std.cstream;
import std.format;
import std.path;
import std.c.windows.windows;

// MBSunicode変換API
extern(Windows) export int MultiByteToWideChar(
uint CodePage,
uint dwFlags,
char* lpMultiByteStr,
int cchMultiByte,
wchar* lpWideCharStr,
int cchWideChar);

// unicodeMBS変換(非ゼロ終端)
ubyte[] toMBS(char[] s)
{
char[] result;
wchar* ws = std.utf.toUTF16z(s);

result.length = WideCharToMultiByte(0, 0, ws, -1, null, 0, null, null);
WideCharToMultiByte(0, 0, ws, -1, result, result.length, null, null);

return cast(ubyte[])result;
}

// MBSunicode変換
wchar[] toWCS(char[] s)
{
wchar[] result;
result.length = MultiByteToWideChar(0, 0, cast(char*)s, s.length,
null, 0);
MultiByteToWideChar(0, 0, cast(char*)s, s.length,cast(wchar*)result,
result.length);
return result;
}

// writefのMBS出力バージョン
void mbswritef(...)
{
char[] s;
ubyte[] mbs;

void puts(dchar c) {
std.utf.encode(s, c);
} std.format.doFormat(&puts, _arguments, _argptr);

mbs = toMBS(s);

int len = mbs.length;
if(len > 0 )
{
std.cstream.dout.writeBlock(mbs.ptr, len-1);// 終端文字を出力していたバグを修正
}
}

void main(char[][] args)
{
while(!din.eof())
{
char[] line = din.readLine();// 中身はMBS
if( line.length == 0 )
{
break;
}
wchar[] wide = toWCS(line);// UTF16に変換
char[] filename = getBaseName(toUTF8(wide));// UTF8に変換
mbswritef("%s\n", filename);// UTF8を与えてMBSで出力
}
}

標準入力から受け取ったフルパスのファイル名のリストから,ファイル名部分だけを切り取るプログラムです.
一応書いておくと,使い方はこんな感じ.


$ dir /s/b/n
C:\D\projects\writef\shell.bat
C:\D\projects\writef\writef.d
C:\D\projects\writef\writef.exe
C:\D\projects\writef\writef.map
C:\D\projects\writef\writef.obj
C:\D\projects\zips2zip\makeerror.log
C:\D\projects\zips2zip\makefile
C:\D\projects\zips2zip\shell.bat
C:\D\projects\zips2zip\zips2zip.d
C:\D\projects\zips2zip\zips2zip.exe
C:\D\projects\zips2zip\zips2zip.map
C:\D\projects\zips2zip\zips2zip.obj

$ dir /s/b/n | chopfname
shell.bat
writef.d
writef.exe
writef.map
writef.obj
makeerror.log
makefile
shell.bat
zips2zip.d
zips2zip.exe
zips2zip.map
zips2zip.obj

いやはや,それにしても mbswritef() のコードを読んで愕然.
ストリームってそんなことまでできるんですねと.

まあ,なんか間違っているかもしれないけど,試してみた限りでは正常に動いている.
必要あらば参考にしてください.