Skip to content

rewrite calltree #151

@wanghenshui

Description

@wanghenshui

#include
#include
#include
#include
#include
#include
#include
#include
#include <unistd.h>
#include <sys/wait.h>
#include
#include <sys/types.h>
#include <sys/stat.h>

// Helper function
std::string exec_cmd(const std::string& cmd) {
char buffer[128];
std::string result;
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) throw std::runtime_error("popen() failed!");
try {
while (fgets(buffer, sizeof buffer, pipe) != nullptr) {
result += buffer;
}
} catch (...) {
pclose(pipe);
throw;
}
pclose(pipe);
return result;
}

bool file_exists(const std::string& filename) {
struct stat buffer;
return (stat(filename.c_str(), &buffer) == 0);
}

void ensure_ag_installed() {
std::string ag_path = exec_cmd("which ag 2>/dev/null");
if (ag_path.empty() || !file_exists(ag_path)) {
std::cerr << "ag is missing, please install ag first, refer to https://github.com/ggreer/the_silver_searcher;\n"
<< "the fork https://github.com/satanson/the_silver_searcher provides a --multiline-break options "
<< "that will generate exact results because the modified ag inserts breaks (--) between two function definitions "
<< "that are not separated by blank lines." << std::endl;
exit(1);
}
}

bool multiline_break_enabled() {
std::string enabled = exec_cmd("echo enabled | ag --multiline-break enabled 2>/dev/null");
std::string trimmed = enabled;
trimmed.erase(trimmed.find_last_not_of(" \n\r\t") + 1);
return trimmed == "enabled";
}

void ensure_safe() {
const char* cwd = getenv("PWD");
const char* home = getenv("HOME");
assert(cwd && home);

std::map<std::string, bool> supported_os_map = {{"Linux", true}, {"Darwin", true}};
std::string os = exec_cmd("uname -s 2>/dev/null");
os.erase(os.find_last_not_of(" \n\r\t") + 1);

if (supported_os_map.find(os) == supported_os_map.end()) {
    std::cerr << "Platform '" << os << "' is not supported, run calltree.cpp in [Linux | Darwin]" << std::endl;
    exit(EXIT_FAILURE);
}

if (std::string(cwd) == std::string(home)) {
    std::cerr << "Never run calltree.cpp in HOME directory: '" << home << "'" << std::endl;
    exit(EXIT_FAILURE);
}
if (std::string(cwd) == "/") {
    std::cerr << "Never run calltree.cpp in root directory: '" << cwd << "'" << std::endl;
    exit(EXIT_FAILURE);
}
size_t levels = std::count(std::string(cwd).begin(), std::string(cwd).end(), '/');
if (levels <= 2) {
    std::cerr << "Never run calltree.cpp in a directory whose depth <= 2" << std::endl;
    exit(EXIT_FAILURE);
}

}

std::vectorstd::string search_matched_lines(const std::string& re) {
std::string multiline_break = "";
if (multiline_break_enabled()) {
multiline_break = " --multiline-break";
}
std::string cmd = "ag" + multiline_break + " -U -G " + cpp_filename_pattern + " " + ignore_pattern + " '" + re + "'";
std::string result = exec_cmd(cmd);
std::istringstream iss(result);
std::vectorstd::string lines;
std::string line;
while (std::getline(iss, line)) {
lines.push_back(line);
}
// Merge and filter lines as needed, following the logic extracted from the original Perl script
return lines;
}

void preprocess_cpp_files(const std::vectorstd::string& files) {
for (const auto& file : files) {
if (!file_exists(file)) continue;
std::string saved_file = file + ".saved_by_calltree";
std::filesystem::rename(file, saved_file);
std::ifstream in(saved_file);
std::stringstream buffer;
buffer << in.rdbuf();
writeFile(file, buffer.str()); // Add writeFile function as needed
// Apply preprocessing actions here
}
}

std::string show_tree() {
ensure_safe();
ensure_ag_installed();
// Placeholder for the get_cached_or_extract_all_funcs call
/*
auto [Global_calling, Global_called, Global_calling_names, Global_called_names] = get_cached_or_extract_all_funcs(%ignored, env_trivial_threshold, env_length_threshold);
*/
int Opt_mode = 0; // Default value
std::string tree;
std::vectorstd::string lines;
if (Opt_mode == 0) {
tree = unified_calling_tree(Opt_func, Opt_func_match_rule, Opt_file_match_rule, Opt_depth);
lines = format_calling_tree(tree, Opt_verbose);
return join(lines.begin(), lines.end(), "\n"); // Add join function as needed
} else if (Opt_mode == 1) {
// Handle mode 1
} else if (Opt_mode == 4) {
auto match_lines = search_matched_lines(Opt_func);
tree = search_called_tree(Global_called, Opt_func, match_lines, Opt_func_match_rule, Opt_file_match_rule, Opt_depth);
lines = format_called_tree(tree, Opt_verbose);
return join(lines.begin(), lines.end(), "\n");
}
return "";
}

int main() {
std::vectorstd::string key; // Initialize key as needed
std::string cached_file = "cached_sha256_file"; // Assign appropriate cached file
std::string result = get_cache_or_run_keyed(key, cached_file, show_tree); // Implement the get_cache_or_run_keyed function as needed
std::cout << result;

return 0;

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions