MinGW対応

MinGWで\+CR/LFが通ることに今更ながら気付き、HamigakiライブラリをMinGWに対応させました。
実質、UNIXでliboggとlibvorbisをソースからビルドさせた場合のバグ修正です。
cygwinではバイナリパッケージを使用していたため、気が付きませんでした。テスト不足ですね。
なお、MinGWで使用する場合はliboggのバージョンを1.1.2以上にする必要があります。
今日の成果物
ちなみにcygwinコンパイルするために、こんなツールを使っています。

#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/newline.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <exception>
#include <iostream>

namespace fs = boost::filesystem;
namespace io = boost::iostreams;

bool is_binary_ext(const std::string& ext)
{
    return (ext != ".cpp") && (ext != ".hpp");
}

bool is_ide_directory(const fs::path& ph)
{
    typedef fs::directory_iterator DI;
    for (DI i(ph), end; i != end; ++i)
        if (fs::extension(*i) == ".sln")
            return true;
    return false;
}

void convert(const fs::path& src, const fs::path& dst)
{
    if (fs::create_directory(dst))
        std::cout << "D " << dst.string() << '\n';

    typedef fs::directory_iterator DI;
    for (DI i(src), end; i != end; ++i)
    {
        if (fs::is_directory(*i))
        {
            if (i->leaf() == ".svn")
                continue;
            else if (i->leaf() == "bin")
                continue;
            else if (i->leaf() == "stage")
                continue;
            else if (is_ide_directory(*i))
                continue;

            convert(*i, dst / i->leaf());
        }
        else
        {
            const fs::path& dst_path = dst / i->leaf();
            std::time_t src_time = fs::last_write_time(*i);
            try
            {
                std::time_t dst_time = fs::last_write_time(dst_path);
                if (src_time == dst_time)
                    continue;
            }
            catch (const fs::filesystem_error&)
            {
            }

            if (is_binary_ext(fs::extension(i->leaf())))
            {
                fs::remove(dst_path);
                fs::copy_file(*i, dst_path);
                fs::last_write_time(dst_path, src_time);
                std::cout << "B " << dst_path.string() << '\n';
            }
            else
            {
                io::filtering_istreambuf in(
                    io::newline_filter(io::newline::posix) |
                    io::file_source(i->string(), BOOST_IOS::binary)
                );

                io::copy(
                    in,
                    io::file_sink(dst_path.string(), BOOST_IOS::binary));

                fs::last_write_time(dst_path, src_time);
                std::cout << "T " << dst_path.string() << '\n';
            }
        }
    }
}

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 3)
        {
            std::cerr << "Usage: win2unix (src-dir) (dst-dir)" << std::endl;
            return 1;
        }

        convert(fs::path(argv[1]), fs::path(argv[2]));

        return 0;
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return 1;
}

Subversionの改行自動変換を使う手もあるんですが、コミット前に動作確認したいのと、複数ディレクトリで編集作業をするのが面倒なのでこうしています。実際はさらにbashエイリアスを張っています。
また、初期バージョンではfile_descriptor_sinkを使っていましたが、オープンモードのバグに気が付いてfile_sinkに変更しました。