diff --git a/src/prodir/cpp/bindings.cpp b/src/prodir/cpp/bindings.cpp index 625c630..141b82e 100644 --- a/src/prodir/cpp/bindings.cpp +++ b/src/prodir/cpp/bindings.cpp @@ -27,9 +27,17 @@ static PyObject* get_structure(PyObject* self, PyObject* args) { std::string path_str = path ? path : ""; std::vector structure = g_tree_structurer->get_directory_structure(path_str); PyObject* list = PyList_New(structure.size()); + if (!list) { + return NULL; + } for (size_t i = 0; i < structure.size(); i++) { - PyList_SET_ITEM(list, i, PyUnicode_FromString(structure[i].c_str())); - } + PyObject* str = PyUnicode_FromString(structure[i].c_str()); + if (!str) { + Py_DECREF(list); + return NULL; + } + PyList_SET_ITEM(list, i, str); + } return list; } catch (const std::exception& e) { PyErr_SetString(TreeStructurerError, e.what()); @@ -39,8 +47,7 @@ static PyObject* get_structure(PyObject* self, PyObject* args) { static PyObject* create_structure_from_file(PyObject* self, PyObject* args) { const char* structure_file = nullptr; - const char* target_path = nullptr; - + const char* target_path = "."; // Default to current directory if (!PyArg_ParseTuple(args, "s|s", &structure_file, &target_path)) { return NULL; } @@ -51,8 +58,7 @@ static PyObject* create_structure_from_file(PyObject* self, PyObject* args) { } try { - std::string target_path_str = target_path ? target_path : ""; - g_tree_structurer->create_structure_from_file(structure_file, target_path_str); + g_tree_structurer->create_structure_from_file(structure_file, target_path); Py_RETURN_NONE; } catch (const std::exception& e) { PyErr_SetString(TreeStructurerError, e.what()); @@ -62,25 +68,24 @@ static PyObject* create_structure_from_file(PyObject* self, PyObject* args) { static PyObject* create_structure_from_string(PyObject* self, PyObject* args) { const char* structure_str = nullptr; - const char* target_path = nullptr; + const char* target_path = "."; // Default to current directory if (!PyArg_ParseTuple(args, "s|s", &structure_str, &target_path)) { return NULL; } - + if (g_tree_structurer == nullptr) { PyErr_SetString(TreeStructurerError, "TreeStructurer not initialized"); return NULL; } try { - std::string target_path_str = target_path ? target_path : ""; - g_tree_structurer->create_structure_from_string(structure_str, target_path_str); + g_tree_structurer->create_structure_from_string(structure_str, target_path); Py_RETURN_NONE; } catch (const std::exception& e) { PyErr_SetString(TreeStructurerError, e.what()); return NULL; - } +} } static PyMethodDef TreeStructurerMethods[] = { @@ -97,7 +102,7 @@ static PyMethodDef TreeStructurerMethods[] = { static struct PyModuleDef tree_structurer_module = { PyModuleDef_HEAD_INIT, - "_tree_structurer", // Changed module name to match Python import + "_tree_structurer", "Module for analyzing and creating directory structures", -1, TreeStructurerMethods diff --git a/src/prodir/cpp/tree_structurer.cpp b/src/prodir/cpp/tree_structurer.cpp index 67dffce..bf8f097 100644 --- a/src/prodir/cpp/tree_structurer.cpp +++ b/src/prodir/cpp/tree_structurer.cpp @@ -209,32 +209,57 @@ void TreeStructurer::validate_structure(const std::vector& lines) { } } + +size_t TreeStructurer::get_indent_level(const std::string& line) { + size_t level = 0; + for (size_t i = 0; i < line.length(); ++i) { + if (line[i] == ' ') { + continue; + } + if (line[i] == '-' || + static_cast(line[i]) == INDENT_MARKER_PIPE || + static_cast(line[i]) == INDENT_MARKER_DASH || + static_cast(line[i]) == INDENT_MARKER_END) { + level++; + } else { + break; + } + } + return level / 4; +} + + TreeStructurer::TreeNode TreeStructurer::build_tree_from_lines(const std::vector& lines) { - TreeNode root{"root", true, {}}; + TreeNode root{"root", false, {}}; std::vector stack{&root}; size_t prev_indent = 0; - + for (const auto& line : lines) { + if (line.empty()) continue; + size_t current_indent = get_indent_level(line); - + while (current_indent <= prev_indent && stack.size() > 1) { stack.pop_back(); prev_indent--; } - + TreeNode new_node = parse_structure_line(line, current_indent); - stack.back()->children.push_back(new_node); - - if (!new_node.is_file) { - stack.push_back(&(stack.back()->children.back())); + if (!new_node.name.empty()) { + stack.back()->children.push_back(new_node); + + if (!new_node.is_file) { + stack.push_back(&(stack.back()->children.back())); + } + + prev_indent = current_indent; } - - prev_indent = current_indent; } - + return root; } + void TreeStructurer::create_node(const TreeNode& node, const std::filesystem::path& current_path) { std::filesystem::path new_path = current_path / node.name; @@ -272,44 +297,27 @@ TreeStructurer::TreeNode TreeStructurer::parse_structure_line(const std::string& static_cast(line[i]) != INDENT_MARKER_PIPE && static_cast(line[i]) != INDENT_MARKER_DASH && static_cast(line[i]) != INDENT_MARKER_END && - line[i] != '-') { + line[i] != '-' && + line[i] != '├' && + line[i] != '└') { name_start = i; break; } } std::string name = line.substr(name_start); - name.erase(0, name.find_first_not_of(" ")); name.erase(name.find_last_not_of(" ") + 1); - bool is_file = !is_directory_marker(name); + bool is_file = name.empty() || name.back() != '/'; - if (!is_file && name.back() == '/') { + if (!is_file) { name.pop_back(); } return TreeNode{name, is_file, {}}; } -size_t TreeStructurer::get_indent_level(const std::string& line) { - size_t level = 0; - for (size_t i = 0; i < line.length(); ++i) { - if (line[i] == ' ') { - continue; - } - if (line[i] == '-' || - static_cast(line[i]) == INDENT_MARKER_PIPE || - static_cast(line[i]) == INDENT_MARKER_DASH || - static_cast(line[i]) == INDENT_MARKER_END) { - level++; - } else { - break; - } - } - return level / 4; -} - bool TreeStructurer::is_directory_marker(const std::string& line) { return !line.empty() && line.back() == DIRECTORY_MARKER; } diff --git a/src/prodir/cpp/tree_structurer.hpp b/src/prodir/cpp/tree_structurer.hpp index ddcdee0..f9c020e 100644 --- a/src/prodir/cpp/tree_structurer.hpp +++ b/src/prodir/cpp/tree_structurer.hpp @@ -17,9 +17,9 @@ public: private: struct TreeNode { - std::string name; - bool is_file; - std::vector children; + std::string name; + bool is_file; + std::vector children; }; bool should_ignore_dir(const std::string& dirname); @@ -27,11 +27,11 @@ private: std::string create_indent(size_t level); std::string get_relative_path(const std::filesystem::path& path, const std::filesystem::path& base); std::vector get_filtered_paths(const std::filesystem::path& start); - + size_t get_indent_level(const std::string& line); TreeNode parse_structure_line(const std::string& line, size_t indent_level); TreeNode build_tree_from_lines(const std::vector& lines); + void create_node(const TreeNode& node, const std::filesystem::path& current_path); - size_t get_indent_level(const std::string& line); bool is_directory_marker(const std::string& line); void create_directory(const std::filesystem::path& path); void create_file(const std::filesystem::path& path); @@ -42,4 +42,5 @@ private: static const unsigned char INDENT_MARKER_PIPE = '|'; static const unsigned char INDENT_MARKER_DASH = '+'; static const unsigned char INDENT_MARKER_END = '\\'; + };