aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/cgroup.cc4
-rw-r--r--src/libutil/config.cc1
-rw-r--r--src/libutil/current-process.cc1
-rw-r--r--src/libutil/experimental-features.cc1
-rw-r--r--src/libutil/meson.build2
-rw-r--r--src/libutil/namespaces.cc2
-rw-r--r--src/libutil/regex-combinators.hh2
-rw-r--r--src/libutil/serialise.hh1
-rw-r--r--src/libutil/shlex.cc2
-rw-r--r--src/libutil/strings.cc232
-rw-r--r--src/libutil/strings.hh256
-rw-r--r--src/libutil/unix-domain-socket.cc2
-rw-r--r--src/libutil/url.cc2
-rw-r--r--src/libutil/util.cc230
-rw-r--r--src/libutil/util.hh248
15 files changed, 504 insertions, 482 deletions
diff --git a/src/libutil/cgroup.cc b/src/libutil/cgroup.cc
index aa7802f79..e28e21c3e 100644
--- a/src/libutil/cgroup.cc
+++ b/src/libutil/cgroup.cc
@@ -1,15 +1,17 @@
+#include "logging.hh"
#if __linux__
#include "cgroup.hh"
-#include "util.hh"
#include "file-system.hh"
#include "finally.hh"
+#include "strings.hh"
#include <chrono>
#include <cmath>
#include <regex>
#include <unordered_set>
#include <thread>
+#include <signal.h>
#include <dirent.h>
#include <mntent.h>
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index f6f14878a..729b4e596 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -3,6 +3,7 @@
#include "abstract-setting-to-json.hh"
#include "experimental-features.hh"
#include "file-system.hh"
+#include "strings.hh"
#include "config-impl.hh"
diff --git a/src/libutil/current-process.cc b/src/libutil/current-process.cc
index 826e25547..41f591b0c 100644
--- a/src/libutil/current-process.cc
+++ b/src/libutil/current-process.cc
@@ -3,6 +3,7 @@
#include "logging.hh"
#include "signals.hh"
#include "util.hh"
+#include "strings.hh"
#ifdef __APPLE__
# include <mach-o/dyld.h>
diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc
index 25beba467..8ebec2956 100644
--- a/src/libutil/experimental-features.cc
+++ b/src/libutil/experimental-features.cc
@@ -1,6 +1,7 @@
#include "experimental-features.hh"
// Required for instances of to_json and from_json for ExperimentalFeature
#include "experimental-features-json.hh"
+#include "strings.hh"
#include "util.hh"
#include "nlohmann/json.hpp"
diff --git a/src/libutil/meson.build b/src/libutil/meson.build
index 73c520116..b662ea455 100644
--- a/src/libutil/meson.build
+++ b/src/libutil/meson.build
@@ -31,6 +31,7 @@ libutil_sources = files(
'shlex.cc',
'signals.cc',
'source-path.cc',
+ 'strings.cc',
'suggestions.cc',
'tarfile.cc',
'terminal.cc',
@@ -96,6 +97,7 @@ libutil_headers = files(
'signals.hh',
'source-path.hh',
'split.hh',
+ 'strings.hh',
'suggestions.hh',
'sync.hh',
'tarfile.hh',
diff --git a/src/libutil/namespaces.cc b/src/libutil/namespaces.cc
index cde442671..d092e6fcc 100644
--- a/src/libutil/namespaces.cc
+++ b/src/libutil/namespaces.cc
@@ -2,9 +2,9 @@
#include "file-system.hh"
#include "logging.hh"
-#include "util.hh"
#include "namespaces.hh"
#include "processes.hh"
+#include "strings.hh"
#include <sys/mount.h>
diff --git a/src/libutil/regex-combinators.hh b/src/libutil/regex-combinators.hh
index 87d6aa678..37962944e 100644
--- a/src/libutil/regex-combinators.hh
+++ b/src/libutil/regex-combinators.hh
@@ -1,6 +1,8 @@
#pragma once
///@file
+#include "strings.hh"
+
#include <string_view>
namespace nix::regex {
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index d4a14bbf0..e46c5624a 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -3,6 +3,7 @@
#include <memory>
+#include "strings.hh"
#include "types.hh"
#include "util.hh"
#include "file-descriptor.hh"
diff --git a/src/libutil/shlex.cc b/src/libutil/shlex.cc
index b5f340251..21fa0502a 100644
--- a/src/libutil/shlex.cc
+++ b/src/libutil/shlex.cc
@@ -1,5 +1,5 @@
#include "shlex.hh"
-#include "util.hh"
+#include "strings.hh"
namespace nix {
diff --git a/src/libutil/strings.cc b/src/libutil/strings.cc
new file mode 100644
index 000000000..9cb319cce
--- /dev/null
+++ b/src/libutil/strings.cc
@@ -0,0 +1,232 @@
+#include "strings.hh"
+
+namespace nix {
+
+std::vector<char *> stringsToCharPtrs(const Strings & ss)
+{
+ std::vector<char *> res;
+ for (auto & s : ss) res.push_back((char *) s.c_str());
+ res.push_back(0);
+ return res;
+}
+
+
+template<class C> C tokenizeString(std::string_view s, std::string_view separators)
+{
+ C result;
+ auto pos = s.find_first_not_of(separators, 0);
+ while (pos != std::string_view::npos) {
+ auto end = s.find_first_of(separators, pos + 1);
+ if (end == std::string_view::npos) end = s.size();
+ result.insert(result.end(), std::string(s, pos, end - pos));
+ pos = s.find_first_not_of(separators, end);
+ }
+ return result;
+}
+
+template Strings tokenizeString(std::string_view s, std::string_view separators);
+template StringSet tokenizeString(std::string_view s, std::string_view separators);
+template std::vector<std::string> tokenizeString(std::string_view s, std::string_view separators);
+
+
+std::string chomp(std::string_view s)
+{
+ size_t i = s.find_last_not_of(" \n\r\t");
+ return i == std::string_view::npos ? "" : std::string(s, 0, i + 1);
+}
+
+
+std::string trim(std::string_view s, std::string_view whitespace)
+{
+ auto i = s.find_first_not_of(whitespace);
+ if (i == s.npos) return "";
+ auto j = s.find_last_not_of(whitespace);
+ return std::string(s, i, j == s.npos ? j : j - i + 1);
+}
+
+
+std::string replaceStrings(
+ std::string res,
+ std::string_view from,
+ std::string_view to)
+{
+ if (from.empty()) return res;
+ size_t pos = 0;
+ while ((pos = res.find(from, pos)) != std::string::npos) {
+ res.replace(pos, from.size(), to);
+ pos += to.size();
+ }
+ return res;
+}
+
+
+Rewriter::Rewriter(std::map<std::string, std::string> rewrites)
+ : rewrites(std::move(rewrites))
+{
+ for (const auto & [k, v] : this->rewrites) {
+ assert(!k.empty());
+ initials.push_back(k[0]);
+ }
+ std::ranges::sort(initials);
+ auto [firstDupe, end] = std::ranges::unique(initials);
+ initials.erase(firstDupe, end);
+}
+
+std::string Rewriter::operator()(std::string s)
+{
+ size_t j = 0;
+ while ((j = s.find_first_of(initials, j)) != std::string::npos) {
+ size_t skip = 1;
+ for (auto & [from, to] : rewrites) {
+ if (s.compare(j, from.size(), from) == 0) {
+ s.replace(j, from.size(), to);
+ skip = to.size();
+ break;
+ }
+ }
+ j += skip;
+ }
+ return s;
+}
+
+
+std::string toLower(const std::string & s)
+{
+ std::string r(s);
+ for (auto & c : r)
+ c = std::tolower(c);
+ return r;
+}
+
+
+std::string shellEscape(const std::string_view s)
+{
+ std::string r;
+ r.reserve(s.size() + 2);
+ r += "'";
+ for (auto & i : s)
+ if (i == '\'') r += "'\\''"; else r += i;
+ r += '\'';
+ return r;
+}
+
+constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+std::string base64Encode(std::string_view s)
+{
+ std::string res;
+ res.reserve((s.size() + 2) / 3 * 4);
+ int data = 0, nbits = 0;
+
+ for (char c : s) {
+ data = data << 8 | (unsigned char) c;
+ nbits += 8;
+ while (nbits >= 6) {
+ nbits -= 6;
+ res.push_back(base64Chars[data >> nbits & 0x3f]);
+ }
+ }
+
+ if (nbits) res.push_back(base64Chars[data << (6 - nbits) & 0x3f]);
+ while (res.size() % 4) res.push_back('=');
+
+ return res;
+}
+
+
+std::string base64Decode(std::string_view s)
+{
+ constexpr char npos = -1;
+ constexpr std::array<char, 256> base64DecodeChars = [&]() {
+ std::array<char, 256> result{};
+ for (auto& c : result)
+ c = npos;
+ for (int i = 0; i < 64; i++)
+ result[base64Chars[i]] = i;
+ return result;
+ }();
+
+ std::string res;
+ // Some sequences are missing the padding consisting of up to two '='.
+ // vvv
+ res.reserve((s.size() + 2) / 4 * 3);
+ unsigned int d = 0, bits = 0;
+
+ for (char c : s) {
+ if (c == '=') break;
+ if (c == '\n') continue;
+
+ char digit = base64DecodeChars[(unsigned char) c];
+ if (digit == npos)
+ throw Error("invalid character in Base64 string: '%c'", c);
+
+ bits += 6;
+ d = d << 6 | digit;
+ if (bits >= 8) {
+ res.push_back(d >> (bits - 8) & 0xff);
+ bits -= 8;
+ }
+ }
+
+ return res;
+}
+
+
+std::string stripIndentation(std::string_view s)
+{
+ size_t minIndent = 10000;
+ size_t curIndent = 0;
+ bool atStartOfLine = true;
+
+ for (auto & c : s) {
+ if (atStartOfLine && c == ' ')
+ curIndent++;
+ else if (c == '\n') {
+ if (atStartOfLine)
+ minIndent = std::max(minIndent, curIndent);
+ curIndent = 0;
+ atStartOfLine = true;
+ } else {
+ if (atStartOfLine) {
+ minIndent = std::min(minIndent, curIndent);
+ atStartOfLine = false;
+ }
+ }
+ }
+
+ std::string res;
+
+ size_t pos = 0;
+ while (pos < s.size()) {
+ auto eol = s.find('\n', pos);
+ if (eol == s.npos) eol = s.size();
+ if (eol - pos > minIndent)
+ res.append(s.substr(pos + minIndent, eol - pos - minIndent));
+ res.push_back('\n');
+ pos = eol + 1;
+ }
+
+ return res;
+}
+
+
+std::pair<std::string_view, std::string_view> getLine(std::string_view s)
+{
+ auto newline = s.find('\n');
+
+ if (newline == s.npos) {
+ return {s, ""};
+ } else {
+ auto line = s.substr(0, newline);
+ if (!line.empty() && line[line.size() - 1] == '\r')
+ line = line.substr(0, line.size() - 1);
+ return {line, s.substr(newline + 1)};
+ }
+}
+
+std::string showBytes(uint64_t bytes)
+{
+ return fmt("%.2f MiB", bytes / (1024.0 * 1024.0));
+}
+
+}
diff --git a/src/libutil/strings.hh b/src/libutil/strings.hh
new file mode 100644
index 000000000..daeb5be50
--- /dev/null
+++ b/src/libutil/strings.hh
@@ -0,0 +1,256 @@
+#pragma once
+///@file
+
+#include "error.hh"
+#include "types.hh"
+
+#include <boost/lexical_cast.hpp>
+#include <vector>
+
+namespace nix {
+
+/**
+ * Tree formatting.
+ */
+constexpr char treeConn[] = "├───";
+constexpr char treeLast[] = "└───";
+constexpr char treeLine[] = "│ ";
+constexpr char treeNull[] = " ";
+
+/**
+ * Convert a list of strings to a null-terminated vector of `char
+ * *`s. The result must not be accessed beyond the lifetime of the
+ * list of strings.
+ */
+std::vector<char *> stringsToCharPtrs(const Strings & ss);
+
+
+MakeError(FormatError, Error);
+
+
+/**
+ * String tokenizer.
+ */
+template<class C> C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r");
+
+
+/**
+ * Concatenate the given strings with a separator between the
+ * elements.
+ */
+template<class C>
+std::string concatStringsSep(const std::string_view sep, const C & ss)
+{
+ size_t size = 0;
+ // need a cast to string_view since this is also called with Symbols
+ for (const auto & s : ss) size += sep.size() + std::string_view(s).size();
+ std::string s;
+ s.reserve(size);
+ for (auto & i : ss) {
+ if (s.size() != 0) s += sep;
+ s += i;
+ }
+ return s;
+}
+
+template<class ... Parts>
+auto concatStrings(Parts && ... parts)
+ -> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), std::string>
+{
+ std::string_view views[sizeof...(parts)] = { parts... };
+ return concatStringsSep({}, views);
+}
+
+
+/**
+ * Add quotes around a collection of strings.
+ */
+template<class C> Strings quoteStrings(const C & c)
+{
+ Strings res;
+ for (auto & s : c)
+ res.push_back("'" + s + "'");
+ return res;
+}
+
+/**
+ * Remove trailing whitespace from a string.
+ *
+ * \todo return std::string_view.
+ */
+std::string chomp(std::string_view s);
+
+
+/**
+ * Remove whitespace from the start and end of a string.
+ */
+std::string trim(std::string_view s, std::string_view whitespace = " \n\r\t");
+
+
+/**
+ * Replace all occurrences of a string inside another string.
+ */
+std::string replaceStrings(
+ std::string s,
+ std::string_view from,
+ std::string_view to);
+
+
+/**
+ * Rewrites a string given a map of replacements, applying the replacements in
+ * sorted order, only once, considering only the strings appearing in the input
+ * string in performing replacement.
+ *
+ * - Replacements are not performed on intermediate strings. That is, for an input
+ * `"abb"` with replacements `{"ab" -> "ba"}`, the result is `"bab"`.
+ * - Transitive replacements are not performed. For example, for the input `"abcde"`
+ * with replacements `{"a" -> "b", "b" -> "c", "e" -> "b"}`, the result is
+ * `"bccdb"`.
+ */
+class Rewriter
+{
+private:
+ std::string initials;
+ std::map<std::string, std::string> rewrites;
+
+public:
+ explicit Rewriter(std::map<std::string, std::string> rewrites);
+
+ std::string operator()(std::string s);
+};
+
+inline std::string rewriteStrings(std::string s, const StringMap & rewrites)
+{
+ return Rewriter(rewrites)(s);
+}
+
+
+
+/**
+ * Parse a string into an integer.
+ */
+template<class N>
+std::optional<N> string2Int(const std::string_view s)
+{
+ if (s.substr(0, 1) == "-" && !std::numeric_limits<N>::is_signed)
+ return std::nullopt;
+ try {
+ return boost::lexical_cast<N>(s.data(), s.size());
+ } catch (const boost::bad_lexical_cast &) {
+ return std::nullopt;
+ }
+}
+
+/**
+ * Like string2Int(), but support an optional suffix 'K', 'M', 'G' or
+ * 'T' denoting a binary unit prefix.
+ */
+template<class N>
+N string2IntWithUnitPrefix(std::string_view s)
+{
+ N multiplier = 1;
+ if (!s.empty()) {
+ char u = std::toupper(*s.rbegin());
+ if (std::isalpha(u)) {
+ if (u == 'K') multiplier = 1ULL << 10;
+ else if (u == 'M') multiplier = 1ULL << 20;
+ else if (u == 'G') multiplier = 1ULL << 30;
+ else if (u == 'T') multiplier = 1ULL << 40;
+ else throw UsageError("invalid unit specifier '%1%'", u);
+ s.remove_suffix(1);
+ }
+ }
+ if (auto n = string2Int<N>(s))
+ return *n * multiplier;
+ throw UsageError("'%s' is not an integer", s);
+}
+
+/**
+ * Parse a string into a float.
+ */
+template<class N>
+std::optional<N> string2Float(const std::string_view s)
+{
+ try {
+ return boost::lexical_cast<N>(s.data(), s.size());
+ } catch (const boost::bad_lexical_cast &) {
+ return std::nullopt;
+ }
+}
+
+
+/**
+ * Convert a little-endian integer to host order.
+ */
+template<typename T>
+T readLittleEndian(unsigned char * p)
+{
+ T x = 0;
+ for (size_t i = 0; i < sizeof(x); ++i, ++p) {
+ x |= ((T) *p) << (i * 8);
+ }
+ return x;
+}
+
+/**
+ * Convert a string to lower case.
+ */
+std::string toLower(const std::string & s);
+
+
+/**
+ * Escape a string as a shell word.
+ */
+std::string shellEscape(const std::string_view s);
+
+/**
+ * Base64 encoding/decoding.
+ */
+std::string base64Encode(std::string_view s);
+std::string base64Decode(std::string_view s);
+
+
+/**
+ * Remove common leading whitespace from the lines in the string
+ * 's'. For example, if every line is indented by at least 3 spaces,
+ * then we remove 3 spaces from the start of every line.
+ */
+std::string stripIndentation(std::string_view s);
+
+/**
+ * Get the prefix of 's' up to and excluding the next line break (LF
+ * optionally preceded by CR), and the remainder following the line
+ * break.
+ */
+std::pair<std::string_view, std::string_view> getLine(std::string_view s);
+
+std::string showBytes(uint64_t bytes);
+
+
+/**
+ * Provide an addition operator between strings and string_views
+ * inexplicably omitted from the standard library.
+ */
+inline std::string operator + (const std::string & s1, std::string_view s2)
+{
+ auto s = s1;
+ s.append(s2);
+ return s;
+}
+
+inline std::string operator + (std::string && s, std::string_view s2)
+{
+ s.append(s2);
+ return std::move(s);
+}
+
+inline std::string operator + (std::string_view s1, const char * s2)
+{
+ std::string s;
+ s.reserve(s1.size() + strlen(s2));
+ s.append(s1);
+ s.append(s2);
+ return s;
+}
+
+}
diff --git a/src/libutil/unix-domain-socket.cc b/src/libutil/unix-domain-socket.cc
index 9fefcbe1c..a9a2a415a 100644
--- a/src/libutil/unix-domain-socket.cc
+++ b/src/libutil/unix-domain-socket.cc
@@ -1,7 +1,7 @@
#include "file-system.hh"
#include "processes.hh"
#include "unix-domain-socket.hh"
-#include "util.hh"
+#include "strings.hh"
#include <sys/socket.h>
#include <sys/un.h>
diff --git a/src/libutil/url.cc b/src/libutil/url.cc
index afccc4245..46688cef5 100644
--- a/src/libutil/url.cc
+++ b/src/libutil/url.cc
@@ -1,7 +1,7 @@
#include "url.hh"
#include "url-parts.hh"
-#include "util.hh"
#include "split.hh"
+#include "strings.hh"
namespace nix {
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index f580ef038..099a07622 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -1,5 +1,6 @@
#include "util.hh"
#include "processes.hh"
+#include "strings.hh"
#include "current-process.hh"
#include "sync.hh"
@@ -164,116 +165,6 @@ Path createNixStateDir()
-std::vector<char *> stringsToCharPtrs(const Strings & ss)
-{
- std::vector<char *> res;
- for (auto & s : ss) res.push_back((char *) s.c_str());
- res.push_back(0);
- return res;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-
-
-template<class C> C tokenizeString(std::string_view s, std::string_view separators)
-{
- C result;
- auto pos = s.find_first_not_of(separators, 0);
- while (pos != std::string_view::npos) {
- auto end = s.find_first_of(separators, pos + 1);
- if (end == std::string_view::npos) end = s.size();
- result.insert(result.end(), std::string(s, pos, end - pos));
- pos = s.find_first_not_of(separators, end);
- }
- return result;
-}
-
-template Strings tokenizeString(std::string_view s, std::string_view separators);
-template StringSet tokenizeString(std::string_view s, std::string_view separators);
-template std::vector<std::string> tokenizeString(std::string_view s, std::string_view separators);
-
-
-std::string chomp(std::string_view s)
-{
- size_t i = s.find_last_not_of(" \n\r\t");
- return i == std::string_view::npos ? "" : std::string(s, 0, i + 1);
-}
-
-
-std::string trim(std::string_view s, std::string_view whitespace)
-{
- auto i = s.find_first_not_of(whitespace);
- if (i == s.npos) return "";
- auto j = s.find_last_not_of(whitespace);
- return std::string(s, i, j == s.npos ? j : j - i + 1);
-}
-
-
-std::string replaceStrings(
- std::string res,
- std::string_view from,
- std::string_view to)
-{
- if (from.empty()) return res;
- size_t pos = 0;
- while ((pos = res.find(from, pos)) != std::string::npos) {
- res.replace(pos, from.size(), to);
- pos += to.size();
- }
- return res;
-}
-
-
-Rewriter::Rewriter(std::map<std::string, std::string> rewrites)
- : rewrites(std::move(rewrites))
-{
- for (const auto & [k, v] : this->rewrites) {
- assert(!k.empty());
- initials.push_back(k[0]);
- }
- std::ranges::sort(initials);
- auto [firstDupe, end] = std::ranges::unique(initials);
- initials.erase(firstDupe, end);
-}
-
-std::string Rewriter::operator()(std::string s)
-{
- size_t j = 0;
- while ((j = s.find_first_of(initials, j)) != std::string::npos) {
- size_t skip = 1;
- for (auto & [from, to] : rewrites) {
- if (s.compare(j, from.size(), from) == 0) {
- s.replace(j, from.size(), to);
- skip = to.size();
- break;
- }
- }
- j += skip;
- }
- return s;
-}
-
-
-std::string toLower(const std::string & s)
-{
- std::string r(s);
- for (auto & c : r)
- c = std::tolower(c);
- return r;
-}
-
-
-std::string shellEscape(const std::string_view s)
-{
- std::string r;
- r.reserve(s.size() + 2);
- r += "'";
- for (auto & i : s)
- if (i == '\'') r += "'\\''"; else r += i;
- r += '\'';
- return r;
-}
void ignoreException(Verbosity lvl)
@@ -289,120 +180,6 @@ void ignoreException(Verbosity lvl)
} catch (...) { }
}
-constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-std::string base64Encode(std::string_view s)
-{
- std::string res;
- res.reserve((s.size() + 2) / 3 * 4);
- int data = 0, nbits = 0;
-
- for (char c : s) {
- data = data << 8 | (unsigned char) c;
- nbits += 8;
- while (nbits >= 6) {
- nbits -= 6;
- res.push_back(base64Chars[data >> nbits & 0x3f]);
- }
- }
-
- if (nbits) res.push_back(base64Chars[data << (6 - nbits) & 0x3f]);
- while (res.size() % 4) res.push_back('=');
-
- return res;
-}
-
-
-std::string base64Decode(std::string_view s)
-{
- constexpr char npos = -1;
- constexpr std::array<char, 256> base64DecodeChars = [&]() {
- std::array<char, 256> result{};
- for (auto& c : result)
- c = npos;
- for (int i = 0; i < 64; i++)
- result[base64Chars[i]] = i;
- return result;
- }();
-
- std::string res;
- // Some sequences are missing the padding consisting of up to two '='.
- // vvv
- res.reserve((s.size() + 2) / 4 * 3);
- unsigned int d = 0, bits = 0;
-
- for (char c : s) {
- if (c == '=') break;
- if (c == '\n') continue;
-
- char digit = base64DecodeChars[(unsigned char) c];
- if (digit == npos)
- throw Error("invalid character in Base64 string: '%c'", c);
-
- bits += 6;
- d = d << 6 | digit;
- if (bits >= 8) {
- res.push_back(d >> (bits - 8) & 0xff);
- bits -= 8;
- }
- }
-
- return res;
-}
-
-
-std::string stripIndentation(std::string_view s)
-{
- size_t minIndent = 10000;
- size_t curIndent = 0;
- bool atStartOfLine = true;
-
- for (auto & c : s) {
- if (atStartOfLine && c == ' ')
- curIndent++;
- else if (c == '\n') {
- if (atStartOfLine)
- minIndent = std::max(minIndent, curIndent);
- curIndent = 0;
- atStartOfLine = true;
- } else {
- if (atStartOfLine) {
- minIndent = std::min(minIndent, curIndent);
- atStartOfLine = false;
- }
- }
- }
-
- std::string res;
-
- size_t pos = 0;
- while (pos < s.size()) {
- auto eol = s.find('\n', pos);
- if (eol == s.npos) eol = s.size();
- if (eol - pos > minIndent)
- res.append(s.substr(pos + minIndent, eol - pos - minIndent));
- res.push_back('\n');
- pos = eol + 1;
- }
-
- return res;
-}
-
-
-std::pair<std::string_view, std::string_view> getLine(std::string_view s)
-{
- auto newline = s.find('\n');
-
- if (newline == s.npos) {
- return {s, ""};
- } else {
- auto line = s.substr(0, newline);
- if (!line.empty() && line[line.size() - 1] == '\r')
- line = line.substr(0, line.size() - 1);
- return {line, s.substr(newline + 1)};
- }
-}
-
//////////////////////////////////////////////////////////////////////
@@ -460,9 +237,4 @@ void unshareFilesystem()
}
-std::string showBytes(uint64_t bytes)
-{
- return fmt("%.2f MiB", bytes / (1024.0 * 1024.0));
-}
-
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 216693635..907bdf4ed 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -107,193 +107,6 @@ void unshareFilesystem();
/**
- * Convert a list of strings to a null-terminated vector of `char
- * *`s. The result must not be accessed beyond the lifetime of the
- * list of strings.
- */
-std::vector<char *> stringsToCharPtrs(const Strings & ss);
-
-
-MakeError(FormatError, Error);
-
-
-/**
- * String tokenizer.
- */
-template<class C> C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r");
-
-
-/**
- * Concatenate the given strings with a separator between the
- * elements.
- */
-template<class C>
-std::string concatStringsSep(const std::string_view sep, const C & ss)
-{
- size_t size = 0;
- // need a cast to string_view since this is also called with Symbols
- for (const auto & s : ss) size += sep.size() + std::string_view(s).size();
- std::string s;
- s.reserve(size);
- for (auto & i : ss) {
- if (s.size() != 0) s += sep;
- s += i;
- }
- return s;
-}
-
-template<class ... Parts>
-auto concatStrings(Parts && ... parts)
- -> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), std::string>
-{
- std::string_view views[sizeof...(parts)] = { parts... };
- return concatStringsSep({}, views);
-}
-
-
-/**
- * Add quotes around a collection of strings.
- */
-template<class C> Strings quoteStrings(const C & c)
-{
- Strings res;
- for (auto & s : c)
- res.push_back("'" + s + "'");
- return res;
-}
-
-/**
- * Remove trailing whitespace from a string.
- *
- * \todo return std::string_view.
- */
-std::string chomp(std::string_view s);
-
-
-/**
- * Remove whitespace from the start and end of a string.
- */
-std::string trim(std::string_view s, std::string_view whitespace = " \n\r\t");
-
-
-/**
- * Replace all occurrences of a string inside another string.
- */
-std::string replaceStrings(
- std::string s,
- std::string_view from,
- std::string_view to);
-
-
-/**
- * Rewrites a string given a map of replacements, applying the replacements in
- * sorted order, only once, considering only the strings appearing in the input
- * string in performing replacement.
- *
- * - Replacements are not performed on intermediate strings. That is, for an input
- * `"abb"` with replacements `{"ab" -> "ba"}`, the result is `"bab"`.
- * - Transitive replacements are not performed. For example, for the input `"abcde"`
- * with replacements `{"a" -> "b", "b" -> "c", "e" -> "b"}`, the result is
- * `"bccdb"`.
- */
-class Rewriter
-{
-private:
- std::string initials;
- std::map<std::string, std::string> rewrites;
-
-public:
- explicit Rewriter(std::map<std::string, std::string> rewrites);
-
- std::string operator()(std::string s);
-};
-
-inline std::string rewriteStrings(std::string s, const StringMap & rewrites)
-{
- return Rewriter(rewrites)(s);
-}
-
-
-
-/**
- * Parse a string into an integer.
- */
-template<class N>
-std::optional<N> string2Int(const std::string_view s)
-{
- if (s.substr(0, 1) == "-" && !std::numeric_limits<N>::is_signed)
- return std::nullopt;
- try {
- return boost::lexical_cast<N>(s.data(), s.size());
- } catch (const boost::bad_lexical_cast &) {
- return std::nullopt;
- }
-}
-
-/**
- * Like string2Int(), but support an optional suffix 'K', 'M', 'G' or
- * 'T' denoting a binary unit prefix.
- */
-template<class N>
-N string2IntWithUnitPrefix(std::string_view s)
-{
- N multiplier = 1;
- if (!s.empty()) {
- char u = std::toupper(*s.rbegin());
- if (std::isalpha(u)) {
- if (u == 'K') multiplier = 1ULL << 10;
- else if (u == 'M') multiplier = 1ULL << 20;
- else if (u == 'G') multiplier = 1ULL << 30;
- else if (u == 'T') multiplier = 1ULL << 40;
- else throw UsageError("invalid unit specifier '%1%'", u);
- s.remove_suffix(1);
- }
- }
- if (auto n = string2Int<N>(s))
- return *n * multiplier;
- throw UsageError("'%s' is not an integer", s);
-}
-
-/**
- * Parse a string into a float.
- */
-template<class N>
-std::optional<N> string2Float(const std::string_view s)
-{
- try {
- return boost::lexical_cast<N>(s.data(), s.size());
- } catch (const boost::bad_lexical_cast &) {
- return std::nullopt;
- }
-}
-
-
-/**
- * Convert a little-endian integer to host order.
- */
-template<typename T>
-T readLittleEndian(unsigned char * p)
-{
- T x = 0;
- for (size_t i = 0; i < sizeof(x); ++i, ++p) {
- x |= ((T) *p) << (i * 8);
- }
- return x;
-}
-
-/**
- * Convert a string to lower case.
- */
-std::string toLower(const std::string & s);
-
-
-/**
- * Escape a string as a shell word.
- */
-std::string shellEscape(const std::string_view s);
-
-
-/**
* Exception handling in destructors: print an error message, then
* ignore the exception.
*/
@@ -302,38 +115,6 @@ void ignoreException(Verbosity lvl = lvlError);
/**
- * Tree formatting.
- */
-constexpr char treeConn[] = "├───";
-constexpr char treeLast[] = "└───";
-constexpr char treeLine[] = "│ ";
-constexpr char treeNull[] = " ";
-
-
-/**
- * Base64 encoding/decoding.
- */
-std::string base64Encode(std::string_view s);
-std::string base64Decode(std::string_view s);
-
-
-/**
- * Remove common leading whitespace from the lines in the string
- * 's'. For example, if every line is indented by at least 3 spaces,
- * then we remove 3 spaces from the start of every line.
- */
-std::string stripIndentation(std::string_view s);
-
-
-/**
- * Get the prefix of 's' up to and excluding the next line break (LF
- * optionally preceded by CR), and the remainder following the line
- * break.
- */
-std::pair<std::string_view, std::string_view> getLine(std::string_view s);
-
-
-/**
* Get a value for the specified key from an associate container.
*/
template <class T>
@@ -443,33 +224,4 @@ template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
-std::string showBytes(uint64_t bytes);
-
-
-/**
- * Provide an addition operator between strings and string_views
- * inexplicably omitted from the standard library.
- */
-inline std::string operator + (const std::string & s1, std::string_view s2)
-{
- auto s = s1;
- s.append(s2);
- return s;
-}
-
-inline std::string operator + (std::string && s, std::string_view s2)
-{
- s.append(s2);
- return std::move(s);
-}
-
-inline std::string operator + (std::string_view s1, const char * s2)
-{
- std::string s;
- s.reserve(s1.size() + strlen(s2));
- s.append(s1);
- s.append(s2);
- return s;
-}
-
}