CLI and list file support

This commit is contained in:
Guus Waals 2025-05-27 00:06:41 +08:00
parent 5223f1c7c1
commit 54476f89f0
2 changed files with 121 additions and 27 deletions

View File

@ -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)

View File

@ -6,7 +6,9 @@
#include <vector>
#include <regex>
#include <sqlite3.h>
#include "tree_sitter/api.h"
#include <filesystem>
#include <tree_sitter/api.h>
#include <CLI11.hpp>
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] << " <input_file>" << std::endl;
return 1;
std::vector<std::string> readFileList(const std::string& list_file) {
std::vector<std::string> 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<FunctionInfo> 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<std::string> 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<std::string> 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<FunctionInfo> 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;
}