From 0c45e7ac98eab6a8932228f28ccc71865fd95266 Mon Sep 17 00:00:00 2001 From: tastytea Date: Thu, 27 May 2021 14:44:56 +0200 Subject: [PATCH] Add --recursive and --dereference-recursive. Closes: https://schlomp.space/tastytea/epubgrep/issues/5 --- man/epubgrep.1.adoc | 10 ++++++++- src/files.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++ src/files.hpp | 34 +++++++++++++++++++++++++++++ src/main.cpp | 44 +++++++++++++++++++++++++++++++++++--- src/options.cpp | 6 ++++++ 5 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 src/files.cpp create mode 100644 src/files.hpp diff --git a/man/epubgrep.1.adoc b/man/epubgrep.1.adoc index c5c4442..0a55361 100644 --- a/man/epubgrep.1.adoc +++ b/man/epubgrep.1.adoc @@ -2,7 +2,7 @@ :doctype: manpage :Author: tastytea :Email: tastytea@tastytea.de -:Date: 2021-05-26 +:Date: 2021-05-27 :Revision: 0.0.0 :man source: epubgrep :man manual: General Commands Manual @@ -61,6 +61,14 @@ Do not color matches. *--no-filename*:: Suppress the mentioning of file names on output. Chapters and page numbers will still be output. +*-r*, *--recursive*: +Read all files under each directory, recursively, following symbolic links only +if they are on the command line. Silently skips directories that are not +readable by the user. + +*-R*, *--dereference-recursive* +Read all files under each directory, recursively. Follow all symbolic +links. Silently skips directories that are not readable by the user. == USAGE diff --git a/src/files.cpp b/src/files.cpp new file mode 100644 index 0000000..6f28277 --- /dev/null +++ b/src/files.cpp @@ -0,0 +1,52 @@ +/* This file is part of epubgrep. + * Copyright © 2021 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "files.hpp" + +#include "fs-compat.hpp" + +#include +#include +#include +#include + +namespace epubgrep::files +{ + +std::vector list_recursive(const fs::path &directory, + const bool follow_symlinks) +{ + fs::directory_options dir_options{ + fs::directory_options::skip_permission_denied}; + if (follow_symlinks) + { + dir_options |= fs::directory_options::follow_directory_symlink; + } + fs::recursive_directory_iterator dir_iter{directory, dir_options}; + + std::vector paths; + for (const auto &path : dir_iter) + { + if (!path.is_directory()) + { + paths.emplace_back(path); + } + } + + return paths; +} + +} // namespace epubgrep::files diff --git a/src/files.hpp b/src/files.hpp new file mode 100644 index 0000000..93e7dae --- /dev/null +++ b/src/files.hpp @@ -0,0 +1,34 @@ +/* This file is part of epubgrep. + * Copyright © 2021 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef EPUBGREP_FILES_HPP +#define EPUBGREP_FILES_HPP + +#include "fs-compat.hpp" + +#include +#include + +namespace epubgrep::files +{ + +//! List files in directory recursively. +[[nodiscard]] std::vector list_recursive(const fs::path &directory, + bool follow_symlinks); + +} // namespace epubgrep::files + +#endif // EPUBGREP_FILES_HPP diff --git a/src/main.cpp b/src/main.cpp index 9a19ed3..d326dc5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,8 @@ * along with this program. If not, see . */ +#include "files.hpp" +#include "fs-compat.hpp" #include "options.hpp" #include "search.hpp" @@ -78,6 +80,8 @@ int main(int argc, char *argv[]) return EXIT_SUCCESS; } + int return_code{EXIT_SUCCESS}; + vector input_files; if (vm.count("input-file") == 0) { @@ -87,10 +91,44 @@ int main(int argc, char *argv[]) } for (const auto &filepath : vm["input-file"].as>()) { - input_files.emplace_back(filepath); - } + if (vm.count("recursive") + vm.count("dereference-recursive") == 0) + { - int return_code{EXIT_SUCCESS}; + input_files.emplace_back(filepath); + } + else + { + bool follow_symlinks{false}; + if (vm.count("dereference-recursive") > 0) + { + follow_symlinks = true; + } + + try + { + auto files_in_dir{ + files::list_recursive(filepath, follow_symlinks)}; + input_files.insert(input_files.end(), files_in_dir.begin(), + files_in_dir.end()); + } + catch (const fs::filesystem_error &e) + { + if (e.code().value() == 20) + { // Is not a directory. + input_files.emplace_back(filepath); + continue; + } + + cerr << '\n' + << format(translate("ERROR: Could not open {0:s}: {1:s}") + .str() + .data(), + e.path1(), e.what()) + << '\n'; + return_code = EXIT_FAILURE; + } + } + } search::options opts; if (vm.count("basic-regexp") > 0) diff --git a/src/options.cpp b/src/options.cpp index 0bd6c98..a1d6929 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -76,6 +76,12 @@ po::variables_map parse_options(int argc, char *argv[]) ("no-filename", translate("Suppress the mentioning of file names on output.") .str().data()) + ("recursive,r", + translate("Read all files under each directory, recursively.") + .str().data()) + ("dereference-recursive,R", + translate("Read all files under each directory, recursively, " + "following symlinks.") .str().data()) ; po::options_description options_hidden("Hidden options");