picker/include/picker.hpp

592 lines
19 KiB
C++

#pragma once
#include <sys/time.h>
#include <chrono>
#include <regex>
#include <set>
#include <unistd.h>
#include <filesystem>
#include <functional>
#include "type.hpp"
#include "json.hpp"
#include "inja.hpp"
#include "CLI11.hpp"
#include "version.hpp"
#include "appimage/configuration.hpp"
extern std::map<std::string, std::string> lang_lib_map;
extern std::map<std::string, std::string> display_names;
namespace picker {
extern bool is_debug;
extern char *lib_random_hash;
#define PK_OUTPUT(o, fmt, ...) \
{ \
fprintf(o, fmt, ##__VA_ARGS__); \
}
#define PK_MESSAGE(fmt, ...) \
{ \
PK_OUTPUT(stdout, fmt, ##__VA_ARGS__); \
PK_OUTPUT(stdout, "%s\n", ""); \
}
#define PK_ERROR(fmt, ...) \
{ \
PK_OUTPUT(stderr, "%s", "\033[31m") \
PK_OUTPUT(stderr, fmt, ##__VA_ARGS__) \
PK_OUTPUT(stderr, "%s\n", "\033[0m") \
}
#define PK_DEBUG(fmt, ...) \
{ \
if (is_debug) { \
PK_OUTPUT(stderr, "%s", "debug> "); \
PK_OUTPUT(stderr, fmt, ##__VA_ARGS__); \
PK_OUTPUT(stderr, "%s\n", "") \
} \
}
#define PK_FATAL(fmt, ...) \
{ \
PK_OUTPUT(stderr, "%sFatal: ", "\033[31m") \
PK_OUTPUT(stderr, fmt, ##__VA_ARGS__); \
PK_OUTPUT(stderr, "%s\n", "\033[0m") \
exit(-1); \
}
inline void vassert(bool c, std::string msg = "")
{
if (!c) { PK_FATAL("Assert error: %s", msg.c_str()); }
}
inline long vtime()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
inline std::string fmtnow(std::string fmt = "%Y-%m-%d %H:%M:%S")
{
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
std::stringstream buffer;
buffer << std::put_time(&tm, fmt.c_str());
return buffer.str();
}
inline std::string exec(const char *cmd)
{
struct PipeCloser {
void operator()(FILE *pipe) const
{
if (pipe != nullptr) { (void)pclose(pipe); }
}
};
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, PipeCloser> pipe(popen(cmd, "r"));
if (!pipe) { throw std::runtime_error("popen() failed!"); }
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); }
return result;
}
inline std::string trim(std::string s, std::string p)
{
if (s.empty()) { return s; }
s.erase(0, s.find_first_not_of(p));
size_t pos = s.find_last_not_of(p);
if (pos != std::string::npos) { s.erase(pos + 1); }
return s;
}
inline std::string ltrim(std::string s)
{
if (s.empty()) { return s; }
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
return s;
}
inline std::string rtrim(std::string s)
{
if (s.empty()) { return s; }
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
return s;
}
inline std::string trim(std::string s)
{
if (s.empty()) { return s; }
return rtrim(ltrim(s));
}
inline std::vector<std::string> strsplit(std::string str, std::string s = " ")
{
std::cout << "strsplit: '" << str << "' by '" << s << "'" << std::endl;
std::vector<std::string> ret = {};
if (s.empty()) {
auto token = trim(str);
if (!token.empty()) ret.push_back(token);
return ret;
}
size_t start = 0;
size_t end = str.find(s);
while (end != std::string::npos) {
auto sub = str.substr(start, end - start);
sub = trim(sub);
if (!sub.empty()) ret.push_back(sub);
start = end + s.size();
end = str.find(s, start);
}
auto sub = str.substr(start);
sub = trim(sub);
if (!sub.empty()) ret.push_back(sub);
return ret;
}
inline std::string lower_case(std::string input)
{
auto str = input;
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
return str;
}
inline std::string capitalize_first_letter(const std::string &input)
{
if (input.empty()) { return input; }
std::string result = input;
result[0] = std::toupper(result[0]);
return result;
}
// Correctly spelled helpers (preferred)
inline std::map<std::string, std::string> get_default_conflict_map()
{
std::map<std::string, std::string> pin_map;
std::vector<std::string> conflict_pin = {"xclock", "xport", "dut", "initclock",
"step", "stepris", "stepfal", "setwaveform",
"setcoverage", "finish", "refreshcomb"};
for (auto &p : conflict_pin) { pin_map[p] = "pin_"; }
return pin_map;
}
// Backward-compatible wrapper with previous misspelling
inline std::map<std::string, std::string> get_default_confilct_map()
{
return get_default_conflict_map();
}
inline std::string fix_conflict_pin_name(const std::string &in, std::map<std::string, std::string> &pin_map,
bool cap_first = false)
{
auto input = lower_case(in);
if (input.empty()) { PK_FATAL("input pin name is empty"); }
// not find in conflict map
if (pin_map.find(input) == pin_map.end()) {
if (cap_first) { return capitalize_first_letter(in); }
return in;
}
std::string result = pin_map[input] + in;
if (cap_first) { result = capitalize_first_letter(result); }
return result;
}
inline std::string strsplit(std::string str, std::initializer_list<std::string> s, bool front = true)
{
auto ret = str;
for (auto &v : s) {
if (front) {
ret = strsplit(ret, v).front();
} else {
ret = strsplit(ret, v).back();
}
}
return ret;
}
inline bool strconatins(std::string str, std::string subs)
{
return str.find(subs) != std::string::npos;
}
// Correctly spelled alias
inline bool str_contains(const std::string &str, const std::string &subs)
{
return str.find(subs) != std::string::npos;
}
inline std::string streplace(std::string str, std::string s, std::string t = "")
{
std::string input = str;
size_t index = 0;
while (true) {
index = input.find(s, index);
if (index == std::string::npos) break;
input.replace(index, s.length(), t);
index += t.length();
}
return input;
}
inline std::string streplace(std::string str, std::initializer_list<std::string> s, std::string t = "")
{
auto ret = str;
for (auto &v : s) { ret = streplace(ret, v, t); }
return ret;
}
inline std::string str_replace_all(std::string str, const std::string &from, const std::string &to)
{
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
template <typename T>
inline bool contains(const std::vector<T> &v, const T &a)
{
for (const T &x : v) {
if (x == a) return true;
}
return false;
}
// Backward-compatible wrapper with previous misspelling
template <typename T>
inline bool contians(const std::vector<T> &v, const T &a)
{
return contains(v, a);
}
template <typename T, typename F>
inline std::vector<T> key_as_vector(std::map<T, F> &input)
{
std::vector<T> keys;
for (const auto &pair : input) { keys.push_back(pair.first); }
return keys;
}
inline std::string join_str_vec(const std::vector<std::string> &strings, const std::string &delimiter)
{
if (strings.empty()) return "";
std::string result = strings[0];
for (size_t i = 1; i < strings.size(); ++i) { result += delimiter + strings[i]; }
return result;
}
inline bool file_exists(std::string f)
{
return access(f.c_str(), F_OK) == 0;
}
inline std::string exec_result(std::string cmd, int index)
{
auto result = strsplit(exec(cmd.c_str()));
if (result.size() <= index) { return ""; }
return result[index];
}
inline std::string first_uppercase(const std::string &input)
{
return capitalize_first_letter(input);
}
// Backward-compatible wrapper with previous misspelling
inline std::string first_upercase(const std::string &input)
{
return first_uppercase(input);
}
inline std::string base_name(std::string const &path, bool with_subfix = true)
{
auto fname = path.substr(path.find_last_of("/\\") + 1);
if (with_subfix) { return fname; }
return strsplit(fname, ".")[0];
}
inline std::string get_path(std::string str)
{
auto found = str.find_last_of("/\\");
return str.substr(0, found);
}
inline std::string normal_path(std::string path)
{
return std::filesystem::absolute(path).lexically_normal().string();
}
inline std::string path_join(std::initializer_list<std::string> args)
{
std::string path, value;
auto size = args.size();
for (auto p : args) {
if (path.empty()) {
path = p;
path.erase(path.find_last_not_of("/\\") + 1);
continue;
}
auto v = trim(p, "/");
v = trim(v, "\\");
path.append("/" + v);
}
return normal_path(path);
}
inline std::string current_path()
{
return std::filesystem::current_path().string();
}
template <typename... Args>
std::string sfmt(const std::string &format, Args... args)
{
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
if (size_s <= 0) { throw std::runtime_error("Error during formatting."); }
auto size = static_cast<size_t>(size_s);
std::unique_ptr<char[]> buf(new char[size]);
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(),
buf.get() + size - 1); // We don't want the '\0' inside
}
inline std::string version()
{
return "v0.1";
}
inline std::string find_file(std::vector<std::string> fs)
{
for (auto f : fs) {
if (file_exists(f)) {
PK_DEBUG("find file: %s", f.c_str());
return f;
}
}
vassert(false, "search file fail");
return "";
}
inline bool write_file(std::string fname, std::string text)
{
PK_MESSAGE("Write file: %s", fname.c_str());
std::ofstream ofile(fname, std::ios::trunc);
vassert(ofile.is_open(), "write file(" + fname + ") error");
ofile << text;
ofile.close();
return true;
}
inline std::string read_file(std::string fname)
{
std::ifstream ifile(fname, std::ios::in | std::ios::binary);
if (ifile) {
std::string content;
ifile.seekg(0, std::ios::end);
content.resize(ifile.tellg());
ifile.seekg(0, std::ios::beg);
ifile.read(&content[0], content.size());
ifile.close();
return content;
}
throw(errno);
}
inline std::string read_params(std::string fname)
{
PK_MESSAGE("Read params from: %s", fname.c_str());
std::ifstream ifile(fname);
std::string ret;
if (ifile.is_open()) {
std::string line_txt;
while (std::getline(ifile, line_txt)) {
// Remove comments (anything after '#') and trim
auto hash_pos = line_txt.find('#');
if (hash_pos != std::string::npos) { line_txt.erase(hash_pos); }
line_txt = trim(line_txt);
if (line_txt.empty()) { continue; }
if (ret.empty()) {
ret = line_txt;
} else {
ret = ret + " " + line_txt;
}
}
}
return ret;
};
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
#include <windows.h>
inline std::string get_executable_path()
{
char buffer[MAX_PATH];
GetModuleFileName(NULL, buffer, MAX_PATH);
return std::string(buffer);
}
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
inline std::string get_executable_path()
{
char buffer[1024];
uint32_t size = sizeof(buffer);
if (_NSGetExecutablePath(buffer, &size) == 0)
return std::string(buffer);
else
return std::string("");
}
#elif defined(__linux__)
#include <unistd.h>
inline std::string get_executable_path()
{
char buffer[1024];
ssize_t len = ::readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
if (len != -1) {
buffer[len] = '\0';
return std::string(buffer);
} else {
return std::string("");
}
}
#endif
inline bool str_start_with(std::string str, std::string prefix)
{
return str.find(prefix) == 0;
}
inline bool str_start_with_digit(const std::string &str)
{
if (str.empty()) return false;
return std::isdigit(str[0]);
}
inline std::string get_target_path_from(std::string base, std::vector<std::string> paths)
{
auto path = get_executable_path();
for (auto &l : paths) {
auto p = std::string(l);
if (!str_start_with(p, "/")) { p = path_join({base, p}); }
if (file_exists(p)) { return p; }
}
return "";
}
inline std::string get_target_path_from(std::string base, std::initializer_list<std::string> paths)
{
return get_target_path_from(base, std::vector<std::string>(paths));
}
inline std::string get_xcomm_location()
{
if (appimage::is_running_as_appimage()) {
// If running as AppImage, use the appimage configuration to get the xcomm location
return appimage::get_picker_lib("");
}
auto path = get_executable_path();
return get_target_path_from(path, {"../../dependence/xcomm", // 1. search in build dir (for dev)
"./picker", // 2. search in current dir
"../../share/picker", // 3. search in share dir (for install)
"/usr/local/share/picker", // 4. search in /usr/local/share
"/usr/share/picker", // 5. search in /usr/share
"/etc/picker"}); // 6. search in /etc
}
inline std::string get_xcomm_lib(std::string lib_name, std::string &message)
{
auto path = get_xcomm_location();
if (path.empty()) {
message = "xcomm lib not found";
return "";
}
auto lib = path_join({path, lib_name});
if (file_exists(lib)) { return lib; }
message = lib + " not found";
return "";
}
inline std::string get_template_path()
{
if (appimage::is_running_as_appimage()) {
// If running as AppImage, use the appimage configuration to get the template path
return appimage::get_template_path();
}
auto path = get_executable_path();
auto tmp = get_target_path_from(path, {"../../../template", // 1. search in source dir (for dev)
"./template", // 2. search in current dir
"../../share/picker/template", // 3. search in share dir (for install)
"/usr/local/share/picker/template", // 4. search in /usr/local/share
"/etc/picker/template"}); // 5. search in /etc
if (!tmp.empty()) { return tmp; }
PK_FATAL("template not found, please check the installation or manually set the source dir path");
}
inline std::string extract_name(const std::string &input, char delimiter, int isFirst)
{
size_t pos = input.find(delimiter);
if (pos != std::string::npos) {
if (isFirst == 1) {
return input.substr(0, pos);
} else {
return input.substr(pos + 1);
}
}
return input; // 如果没有找到分隔符,则返回整个字符串
}
inline std::string get_env(std::string key, std::string default_value = "")
{
const char *value = std::getenv(key.c_str());
if (value) {
return std::string(value);
} else {
return default_value;
}
}
inline std::string getCurrentTime()
{
auto now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_c);
std::ostringstream oss;
oss << std::put_time(&now_tm, "%Y-%m-%d %H:%M:%S");
return oss.str();
}
inline std::string get_hostname()
{
char hostname[1024];
gethostname(hostname, sizeof(hostname));
return std::string(hostname);
}
inline std::string get_node_uuid()
{
std::hash<std::string> hasher;
return std::to_string(hasher(get_hostname() + std::to_string(getpid())));
}
inline std::string get_shared_lib_suffix()
{
#if defined(_WIN32) || defined(_WIN64)
return "dll";
#elif defined(__linux__)
return "so";
#elif defined(__APPLE__)
return "dylib";
#else
return "";
#endif
}
} // namespace picker