From 54476f89f0558a8f3f0eb49d33501f7239622436 Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Tue, 27 May 2025 00:06:41 +0800 Subject: [PATCH] CLI and list file support --- tooling2/CMakeLists.txt | 3 +- tooling2/tool.cpp | 145 +++++++++++++++++++++++++++++++++------- 2 files changed, 121 insertions(+), 27 deletions(-) diff --git a/tooling2/CMakeLists.txt b/tooling2/CMakeLists.txt index a446198c..227b0dee 100644 --- a/tooling2/CMakeLists.txt +++ b/tooling2/CMakeLists.txt @@ -13,7 +13,8 @@ add_library(sqlite3 target_include_directories(sqlite3 PUBLIC ${SQLITE_SRC}) add_library(CLI11 INTERFACE) -target_include_directories(CLI11 PUBLIC third_party/CLI11) +target_include_directories(CLI11 INTERFACE third_party/CLI11) add_executable(r3_gh_tool tool.cpp) target_link_libraries(r3_gh_tool PRIVATE spdlog::spdlog tree-sitter tree-sitter-cpp sqlite3 CLI11) +target_compile_features(r3_gh_tool PRIVATE cxx_std_23) \ No newline at end of file diff --git a/tooling2/tool.cpp b/tooling2/tool.cpp index 73454f1e..9dadc16a 100644 --- a/tooling2/tool.cpp +++ b/tooling2/tool.cpp @@ -6,7 +6,9 @@ #include #include #include -#include "tree_sitter/api.h" +#include +#include +#include extern "C" TSLanguage *tree_sitter_cpp(); struct FunctionInfo { @@ -296,17 +298,44 @@ void findFunctions(TSNode node, const char* source_code, uint32_t source_length, } } -int main(int argc, char* argv[]) { - if (argc != 2) { - std::cerr << "Usage: " << argv[0] << " " << std::endl; - return 1; +std::vector readFileList(const std::string& list_file) { + std::vector files; + std::ifstream file(list_file); + if (!file.is_open()) { + std::cerr << "Error: Could not open list file " << list_file << std::endl; + return files; } - std::string filepath = argv[1]; + std::string line; + while (std::getline(file, line)) { + // Skip empty lines and comments + if (line.empty() || line[0] == '#') { + continue; + } + + // Handle wildcard patterns like "tmps/gh_fix/*.h" + if (line.find('*') != std::string::npos) { + // For now, skip wildcard patterns as they need more complex handling + std::cout << "Skipping wildcard pattern: " << line << std::endl; + continue; + } + + // Check if file exists + if (std::filesystem::exists(line)) { + files.push_back(line); + } else { + std::cout << "Warning: File not found: " << line << std::endl; + } + } + + return files; +} + +bool processFile(const std::string& filepath, DatabaseManager& db) { std::ifstream file(filepath); if (!file.is_open()) { std::cerr << "Error: Could not open file " << filepath << std::endl; - return 1; + return false; } std::stringstream buffer; @@ -321,38 +350,102 @@ int main(int argc, char* argv[]) { TSNode root_node = ts_tree_root_node(tree); if (ts_node_is_null(root_node)) { - std::cerr << "Error: Failed to parse file" << std::endl; + std::cerr << "Error: Failed to parse file " << filepath << std::endl; + ts_tree_delete(tree); + ts_parser_delete(parser); + return false; + } + + // Clear existing entries for this file + db.clearEntriesForFile(filepath); + + // Find all functions with addresses + std::vector functions; + findFunctions(root_node, source_code, file_content.length(), functions); + + // Insert into database + for (auto& func : functions) { + func.filepath = filepath; + db.insertFunction(func); + + std::cout << (func.is_import ? "Import: " : "Function: ") + << func.name << " @ " << func.address << " in " << filepath << std::endl; + } + + std::cout << "Processed " << functions.size() << " functions/imports from " << filepath << std::endl; + + ts_tree_delete(tree); + ts_parser_delete(parser); + + return true; +} + +int main(int argc, char* argv[]) { + CLI::App app{"C++ Function Parser - Extracts function addresses from C++ files"}; + + std::vector input_files; + std::string list_file; + std::string db_path = "functions.db"; + + // Add options + app.add_option("files", input_files, "Input C++ files to parse (supports @listfile.txt syntax)"); + app.add_option("-l,--list", list_file, "File containing list of files to process"); + app.add_option("-d,--database", db_path, "SQLite database path")->default_val("functions.db"); + + CLI11_PARSE(app, argc, argv); + + // Collect all files to process + std::vector files_to_process; + + // Handle list file option + if (!list_file.empty()) { + auto list_files = readFileList(list_file); + files_to_process.insert(files_to_process.end(), list_files.begin(), list_files.end()); + } + + // Handle input files (including @listfile.txt syntax) + for (const auto& input : input_files) { + if (input.starts_with("@")) { + // Handle @listfile.txt syntax + std::string list_path = input.substr(1); + auto list_files = readFileList(list_path); + files_to_process.insert(files_to_process.end(), list_files.begin(), list_files.end()); + } else { + // Regular file + if (std::filesystem::exists(input)) { + files_to_process.push_back(input); + } else { + std::cout << "Warning: File not found: " << input << std::endl; + } + } + } + + if (files_to_process.empty()) { + std::cerr << "No files to process. Use --help for usage information." << std::endl; return 1; } try { - DatabaseManager db("functions.db"); + DatabaseManager db(db_path); - // Clear existing entries for this file - db.clearEntriesForFile(filepath); + int processed_count = 0; + int total_functions = 0; - // Find all functions with addresses - std::vector functions; - findFunctions(root_node, source_code, file_content.length(), functions); - - // Insert into database - for (auto& func : functions) { - func.filepath = filepath; - db.insertFunction(func); - - std::cout << (func.is_import ? "Import: " : "Function: ") - << func.name << " @ " << func.address << std::endl; + for (const auto& filepath : files_to_process) { + std::cout << "\n=== Processing: " << filepath << " ===" << std::endl; + if (processFile(filepath, db)) { + processed_count++; + } } - std::cout << "Processed " << functions.size() << " functions/imports from " << filepath << std::endl; + std::cout << "\n=== Summary ===" << std::endl; + std::cout << "Processed " << processed_count << " files successfully" << std::endl; + std::cout << "Database saved to: " << db_path << std::endl; } catch (const std::exception& e) { std::cerr << "Database error: " << e.what() << std::endl; return 1; } - ts_tree_delete(tree); - ts_parser_delete(parser); - return 0; }