diff --git a/apps/fsearch/fsearch.cpp b/apps/fsearch/fsearch.cpp index 2093ca6dd485c0f81ec4da34e5db7d0c259846b6..0c4de308c8dfc62f8ca41769573ac77ad026a3d5 100644 --- a/apps/fsearch/fsearch.cpp +++ b/apps/fsearch/fsearch.cpp @@ -1,9 +1,11 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright © 2021-2022 Florian Fischer, Florian Schmaus #include <fcntl.h> +#include <sys/stat.h> #include <unistd.h> #include <array> +#include <atomic> #include <boost/program_options.hpp> #include <climits> #include <cstdlib> @@ -26,13 +28,30 @@ namespace po = boost::program_options; #define EMPER_RIPGREP_BUFSIZE 4096 -const char* needle; -size_t needle_len; +static const char* needle; +static size_t needle_len; -emper::Semaphore* max_running; +static emper::Semaphore* max_running; + +static bool stdoutNeedsOffset = false; +static std::atomic<off_t> stdoutOffset = 0; static enum emper::StealingMode stealingMode; +static void writeFoundPath(const std::string& path) { + std::array<char, PATH_MAX + 1> outBuf; + memcpy(outBuf.data(), path.c_str(), path.length()); + outBuf[path.length()] = '\n'; + + const size_t outLen = path.length() + 1; + + off_t offset = -1; + if (stdoutNeedsOffset) + offset = stdoutOffset.fetch_add(static_cast<off_t>(outLen), std::memory_order_relaxed); + + emper::io::writeFileAndWait(STDOUT_FILENO, outBuf.data(), outLen, offset); +} + void search(const std::string& path) { if (max_running) { max_running->acquire(); @@ -48,10 +67,7 @@ void search(const std::string& path) { ssize_t bytes_read = emper::io::readFileAndWait(fd, buf.data(), buf.size(), 0); while (bytes_read > 0) { if (memmem(&buf[0], bytes_read, needle, needle_len)) { - std::array<char, PATH_MAX + 1> outBuf; - memcpy(outBuf.data(), path.c_str(), path.length()); - outBuf[path.length()] = '\n'; - emper::io::writeFileAndWait(STDOUT_FILENO, outBuf.data(), path.length() + 1, -1); + writeFoundPath(path); goto out; } @@ -105,6 +121,12 @@ static auto fssearch(const po::variables_map& vm) -> int { Runtime runtime; + struct stat statBuf; + int res = fstat(STDOUT_FILENO, &statBuf); + if (res) DIE_MSG_ERRNO("fstat(STDOUT_FILENO) failed"); + + stdoutNeedsOffset = S_ISREG(statBuf.st_mode); + std::cerr << "Starting fsearch with stealingMode=" << stealingMode; if (max_running) std::cerr << " and " << max_running->getCount() << " file fibers"; std::cerr << std::endl;