diff options
Diffstat (limited to 'src/util.cc')
-rw-r--r-- | src/util.cc | 310 |
1 files changed, 241 insertions, 69 deletions
diff --git a/src/util.cc b/src/util.cc index 92560b6..a4abd23 100644 --- a/src/util.cc +++ b/src/util.cc @@ -5,105 +5,70 @@ #include <iostream> #include <fstream> +#include <algorithm> +#include <sstream> +#include <cctype> +#include <cstdlib> + +std::string to_lower(std::string str) +{ + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) + { + return std::tolower(c); + }); + return str; +} std::string readFile(const std::string& fileName) { std::ifstream ifs(fileName.c_str(), std::ios::in | std::ios::binary | std::ios::ate); - std::ifstream::pos_type fileSize = ifs.tellg(); + auto size = ifs.tellg(); + if(size < 0) + { + return {}; + } ifs.seekg(0, std::ios::beg); - std::vector<char> bytes(fileSize); - ifs.read(bytes.data(), fileSize); + std::string bytes(static_cast<std::size_t>(size), '\0'); + ifs.read(bytes.data(), static_cast<std::streamsize>(bytes.size())); - return std::string(bytes.data(), fileSize); + return bytes; } -std::vector<std::string> readDeps(const std::string& depFile) +ctor::language languageFromExtension(const std::filesystem::path& file) { - if(!std::filesystem::exists(depFile)) - { - return {}; - } - - auto str = readFile(depFile); + auto ext = file.extension().string(); - std::vector<std::string> output; - std::string tmp; - bool start{false}; - bool in_whitespace{false}; - for(const auto& c : str) + // First a few case sensitive comparisons + if(ext == ".c") { - if(c == '\\' || c == '\n') - { - continue; - } - - if(c == ':') - { - start = true; - continue; - } - - if(!start) - { - continue; - } - - if(c == ' ' || c == '\t') - { - if(in_whitespace) - { - continue; - } - - if(!tmp.empty()) - { - output.push_back(tmp); - } - tmp.clear(); - in_whitespace = true; - } - else - { - in_whitespace = false; - tmp += c; - } + return ctor::language::c; } - if(!tmp.empty()) + if(ext == ".C") { - output.push_back(tmp); + return ctor::language::cpp; } - return output; -} - -Language languageFromExtension(const std::filesystem::path& file) -{ - auto ext = file.extension().string(); - if(ext == ".c") - { - return Language::C; - } + // The rest are compared in lowercase + ext = to_lower(ext); - if(ext == ".C" || - ext == ".cc" || + if(ext == ".cc" || ext == ".cpp" || - ext == ".CPP" || ext == ".c++" || ext == ".cp" || ext == ".cxx") { - return Language::Cpp; + return ctor::language::cpp; } if(ext == ".s" || - ext == ".S" || ext == ".asm") { - return Language::Asm; + return ctor::language::assembler; } std::cerr << "Could not deduce language from " << file.string() << "\n"; @@ -135,3 +100,210 @@ std::string cleanUp(const std::string& path) } return cleaned; } + +std::string esc(const std::string& in) +{ + std::string out; + for(auto c : in) + { + switch(c) + { + case '\\': out += "\\\\"; break; + case '"': out += "\\\""; break; + default: + out += c; + break; + } + } + return out; +} + +std::vector<std::string> get_paths(const std::string& path_env_) +{ + std::string path_env; + if(!path_env_.empty()) + { + path_env = path_env_; + } + else + { + get_env("PATH", path_env); + } + + std::vector<std::string> paths; + +#ifdef _WIN32 + const char sep{';'}; +#else + const char sep{':'}; +#endif + + std::stringstream ss(path_env); + std::string path; + while (std::getline(ss, path, sep)) + { + paths.push_back(path); + } + + return paths; +} + +bool check_executable(const std::filesystem::path& prog) +{ + auto perms = std::filesystem::status(prog).permissions(); + + if((perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none) + { + return true; + } + + if((perms & std::filesystem::perms::group_exec) != std::filesystem::perms::none) + { + return true; + } + + if((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none) + { + return true; + } + + return false; +} + +std::string locate(const std::string& prog, + const std::vector<std::string>& paths, + const std::string& arch) +{ + std::string program = prog; + if(!arch.empty()) + { + program = arch + "-" + prog; + } + + // first check if arch contains an absolute path to prog + if(std::filesystem::exists(program)) + { + if(check_executable(program)) + { + return program; + } + } + + for(const auto& path_str : paths) + { + std::filesystem::path path(path_str); + auto prog_path = path / program; + if(std::filesystem::exists(prog_path)) + { + if(check_executable(prog_path)) + { + return prog_path.string(); + } + } + } + + return {}; +} + +std::vector<std::string> argsplit(const std::string& str) +{ + enum class state + { + normal, + in_quot, + in_apotrophe, + } state{state::normal}; + bool esc{false}; + + std::string token; + std::vector<std::string> tokens; + for(auto c : str) + { + switch(state) + { + case state::normal: + if(esc) + { + esc = false; + } + else + { + if(c == ' ') + { + tokens.push_back(token); + token.clear(); + continue; + } + if(c == '\\') + { + esc = true; + } + if(c == '"') + { + state = state::in_quot; + } + if(c == '\'') + { + state = state::in_apotrophe; + } + } + + token += c; + break; + case state::in_quot: + if(esc) + { + esc = false; + } + else + { + if(c == '\\') + { + esc = true; + } + if(c == '"') + { + state = state::normal; + } + } + + token += c; + break; + case state::in_apotrophe: + if(esc) + { + esc = false; + } + else + { + if(c == '\\') + { + esc = true; + } + if(c == '\'') + { + state = state::normal; + } + } + + token += c; + break; + } + } + if(!token.empty()) + { + tokens.push_back(token); + } + return tokens; +} + +bool get_env(std::string_view name, std::string& value) +{ + auto var = getenv(name.data()); + if(var) + { + value = var; + return true; + } + return false; +} |