| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 | #include <algorithm>#include <array>#include <cassert>#include <fstream>#include <iostream>#include <memory>#include <numeric>#include <regex>#include <string>#include <vector>std::string escape_arg(const std::string& arg) {    if (arg.empty() == false &&        arg.find_first_of(" \t\n\v\"") == arg.npos) {        return arg;    }    std::string escaped;    escaped.push_back('"');    for (auto it = arg.begin(); ; ++it) {        int num_backslashes = 0;        while (it != arg.end() && *it == '\\') {            ++it;            ++num_backslashes;        }        if (it == arg.end()) {            escaped.append(num_backslashes * 2, '\\');            break;        } else if (*it == '"') {            escaped.append((num_backslashes + 1) * 2, '\\');            escaped.push_back('"');            escaped.push_back(*it);        } else {            escaped.append(num_backslashes, '\\');            escaped.push_back(*it);        }    }    escaped.push_back('"');    return escaped;}void create_empty_file(std::string const& path) {    std::ofstream ofs(path);    ofs << '\n';}const std::string separator = "--sep--";const std::string logfile_prefix = "--log-file=";bool starts_with(std::string const& str, std::string const& pref) {    return str.find(pref) == 0;}int parse_log_file_arg(std::string const& arg) {    assert(starts_with(arg, logfile_prefix) && "Attempting to parse incorrect arg!");    auto fname = arg.substr(logfile_prefix.size());    create_empty_file(fname);    std::regex regex("MemoryChecker\\.(\\d+)\\.log", std::regex::icase);    std::smatch match;    if (std::regex_search(fname, match, regex)) {        return std::stoi(match[1]);    } else {        throw std::domain_error("Couldn't find desired expression in string: " + fname);    }}std::string catch_path(std::string path) {    auto start = path.find("catch");    // try capitalized instead    if (start == std::string::npos) {        start = path.find("Catch");    }    if (start == std::string::npos) {        throw std::domain_error("Couldn't find Catch's base path");    }    auto end = path.find_first_of("\\/", start);    return path.substr(0, end);}std::string windowsify_path(std::string path) {    for (auto& c : path) {        if (c == '/') {            c = '\\';        }    }    return path;}int exec_cmd(std::string const& cmd, int log_num, std::string const& path) {    std::array<char, 128> buffer;    // cmd has already been escaped outside this function.    auto real_cmd = "OpenCppCoverage --export_type binary:cov-report" + std::to_string(log_num)        + ".bin --quiet " + "--sources " + escape_arg(path) + "\\src" + " --cover_children -- " + cmd;    std::cout << "=== Marker ===: Cmd: " << real_cmd << '\n';    auto pipe = _popen(real_cmd.c_str(), "r");    if (!pipe) {        throw std::runtime_error("popen() failed!");    }    while (!feof(pipe)) {        if (fgets(buffer.data(), 128, pipe) != nullptr) {            std::cout << buffer.data();        }    }    auto ret = _pclose(pipe);    if (ret == -1) {        throw std::runtime_error("underlying error in pclose()");    }    return ret;}// argv should be:// [0]: our path// [1]: "--log-file=<path>"// [2]: "--sep--"// [3]+: the actual commandint main(int argc, char** argv) {    std::vector<std::string> args(argv, argv + argc);    auto sep = std::find(begin(args), end(args), separator);    assert(sep - begin(args) == 2 && "Structure differs from expected!");    auto num = parse_log_file_arg(args[1]);    auto cmdline = std::accumulate(++sep, end(args), std::string{}, [] (const std::string& lhs, const std::string& rhs) {        return lhs + ' ' + escape_arg(rhs);    });    try {        return exec_cmd(cmdline, num, windowsify_path(catch_path(args[0])));    } catch (std::exception const& ex) {        std::cerr << "Helper failed with: '" << ex.what() << "'\n";        return 12;    }}
 |