他人の空似自作物置場

run_cmd.zip/run_cmd/main.cpp


#include <iostream>
#include <string>

#include <Windows.h>

#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/program_options.hpp>

int proc(const boost::filesystem::path &path, const std::vector<std::string> &ext, const std::string &cmd, const bool isSilent, const bool isVerbose, const bool isRecursive) {
  if (boost::filesystem::is_directory(path)) {
    if (!isRecursive) {
      return 0;
    }
    int result = 0;
    for (const boost::filesystem::path &item : boost::filesystem::directory_iterator(path)) {
      const int curResult = proc(item, ext, cmd, isSilent, isVerbose, isRecursive);
      if (curResult != 0) {
        result = curResult;
      }
    }
    return result;
  }
  if (!ext.empty() && std::find(ext.begin(), ext.end(), path.extension()) == ext.end()) {
    return 0;
  }
  const std::string target = path.string();
  const std::string cmdline = (boost::format("%s %s") % cmd % target).str();
  const int result = ::system(cmdline.c_str());
  if (isVerbose) {
    if (result == 0) {
      std::cout << boost::format("success: %s\n") % target;
    } else {
      std::cout << boost::format("failure: %s\n") % target;
    }
  }
  if (!isSilent && result != 0) {
    std::cout << boost::format("failure: %s\n") % cmdline;
  }
  return result;
}

int main(const unsigned int argc, const char * const * argv) {
  std::locale loc = std::locale("japanese").combine<std::numpunct<char> >(std::locale::classic()).combine<std::numpunct<wchar_t> >(std::locale::classic());
  std::locale::global(loc);
  std::wcout.imbue(loc);
  std::cout.imbue(loc);

  boost::program_options::variables_map opt_list;
  try {
    using boost::program_options::value;
    boost::program_options::options_description opt("オプション");
    opt.add_options()
      ("help,h", "ヘルプを表示")
      ("silent,s", "標準出力に出さない")
      ("verbose,v", "詳細表示")
      ("recursive,r", "サブディレクトリも対象にする")
      ("ext,e", value<std::vector<std::string> >(), "対象の拡張子")
      ("target,t", value<std::string>(), "対象のファイル/ディレクトリ")
      ("cmd,c", value<std::string>(), "実行するコマンド");
    boost::program_options::positional_options_description pos;
    pos.add("cmd", 1);
    pos.add("target", 1);
    boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(opt).positional(pos).run(), opt_list);
    boost::program_options::notify(opt_list);
    if (opt_list.count("help") != 0 || opt_list.count("target") == 0 || opt_list.count("cmd") == 0) {
      std::wcout << boost::wformat(L"usage: %s [OPTION] [--cmd] cmd [--target] path\n") % boost::filesystem::path(argv[0]).filename().wstring();
      std::cout << opt << std::endl;
      return 1;
    }
  } catch (std::exception& ex) {
    std::cout << "コマンドライン引数の指定に誤りがあります: " << ex.what() << std::endl;
    return 1;
  }

  const boost::filesystem::path target = opt_list["target"].as<std::string>();
  const std::string cmd = opt_list["cmd"].as<std::string>();
  const bool isSilent = (opt_list.count("silent") != 0);
  const bool isVerbose = (opt_list.count("verbose") != 0);
  const bool isRecursive = (opt_list.count("recursive") != 0);
  const std::vector<std::string> ext = opt_list["ext"].as<std::vector<std::string> >();
  if (boost::filesystem::is_regular_file(target)) {
    return proc(target, ext, cmd, isSilent, isVerbose, isRecursive);
  } else if (boost::filesystem::is_directory(target)) {
    int result = 0;
    for (const boost::filesystem::path &item : boost::filesystem::directory_iterator(target)) {
      const int curResult = proc(item, ext, cmd, isSilent, isVerbose, isRecursive);
      if (curResult != 0) {
        result = curResult;
      }
    }
    return result;
  } else {
    std::wcout << L"ファイルもしくはディレクトリを指定してください。\n";
    return 1;
  }
}