commit 43b1524218588d7ad4c1501e471e4b3e66d87165
parent f0e2cbb7ab6450742fbfa8b8e2cb7a735b1e321b
Author: cfillion <cfillion@users.noreply.github.com>
Date: Mon, 11 Sep 2017 04:35:12 -0400
(28500861794ee0a4b1c533ac0bbcaf989394f7c6 done better)
Diffstat:
9 files changed, 115 insertions(+), 39 deletions(-)
diff --git a/src/archive.cpp b/src/archive.cpp
@@ -79,7 +79,8 @@ void Archive::import(const string &path)
stringstream toc;
if(const int err = state.m_reader->extractFile(ARCHIVE_TOC, toc))
- throw reapack_error("Cannot locate the table of contents (%d)", err);
+ throw reapack_error(String::format(
+ "Cannot locate the table of contents (%d)", err));
// starting import, do not abort process (eg. by throwing) at this point
if(!(state.m_tx = g_reapack->setupTransaction()))
@@ -101,7 +102,8 @@ void Archive::import(const string &path)
state.importPackage(data);
break;
default:
- throw reapack_error("Unknown token '%s' (skipping)", line.substr(0, 4).c_str());
+ throw reapack_error(String::format("Unknown token '%s' (skipping)",
+ line.substr(0, 4).c_str()));
}
}
catch(const reapack_error &e) {
@@ -119,8 +121,8 @@ void ImportArchive::importRemote(const string &data)
Remote remote = Remote::fromString(data);
if(const int err = m_reader->extractFile(Index::pathFor(remote.name()))) {
- throw reapack_error("Failed to extract index of %s (%d)",
- remote.name().c_str(), err);
+ throw reapack_error(String::format("Failed to extract index of %s (%d)",
+ remote.name().c_str(), err));
}
const Remote &original = m_remotes->get(remote.name());
@@ -152,10 +154,10 @@ void ImportArchive::importPackage(const string &data)
const Version *ver = pkg ? pkg->findVersion(versionName) : nullptr;
if(!ver) {
- throw reapack_error(
+ throw reapack_error(String::format(
"%s/%s/%s v%s cannot be found or is incompatible with your operating system.",
m_lastIndex->name().c_str(), categoryName.c_str(),
- packageName.c_str(), versionName.c_str());
+ packageName.c_str(), versionName.c_str()));
}
m_tx->install(ver, pinned, m_reader);
@@ -186,8 +188,10 @@ int ArchiveReader::extractFile(const Path &path)
if(FS::open(stream, path))
return extractFile(path, stream);
- else
- throw reapack_error("%s: %s", path.join().c_str(), FS::lastError());
+ else {
+ throw reapack_error(String::format("%s: %s",
+ path.join().c_str(), FS::lastError()));
+ }
}
int ArchiveReader::extractFile(const Path &path, ostream &stream) noexcept
@@ -234,9 +238,8 @@ bool FileExtractor::run()
stream.close();
if(error) {
- char msg[64];
- snprintf(msg, sizeof(msg), "Failed to extract file (%d)", error);
- setError({msg, m_path.target().join()});
+ setError({String::format("Failed to extract file (%d)", error),
+ m_path.target().join()});
return false;
}
@@ -268,8 +271,10 @@ int ArchiveWriter::addFile(const Path &path)
if(FS::open(stream, path))
return addFile(path, stream);
- else
- throw reapack_error("%s: %s", path.join().c_str(), FS::lastError());
+ else {
+ throw reapack_error(String::format("%s: %s",
+ path.join().c_str(), FS::lastError()));
+ }
}
int ArchiveWriter::addFile(const Path &path, istream &stream) noexcept
@@ -307,7 +312,8 @@ bool FileCompressor::run()
{
ifstream stream;
if(!FS::open(stream, m_path)) {
- setError({string("Could not open file for export (") + FS::lastError() + ')',
+ setError({
+ String::format("Could not open file for export (%s)", FS::lastError()),
m_path.join()});
return false;
}
@@ -316,9 +322,7 @@ bool FileCompressor::run()
stream.close();
if(error) {
- char msg[64];
- snprintf(msg, sizeof(msg), "Failed to compress file (%d)", error);
- setError({msg, m_path.join()});
+ setError({String::format("Failed to compress file (%d)", error), m_path.join()});
return false;
}
diff --git a/src/errors.hpp b/src/errors.hpp
@@ -19,23 +19,12 @@
#define REAPACK_ERRORS_HPP
#include <stdexcept>
-#include <string>
+
+#include "string.hpp"
class reapack_error : public std::runtime_error {
public:
using runtime_error::runtime_error;
-
- template<typename... Args> reapack_error(const char *fmt, Args&&... args)
- : runtime_error(format(fmt, std::forward<Args>(args)...)) {}
-
-private:
- template<typename... Args> std::string format(const char *fmt, Args&&... args)
- {
- const int size = snprintf(nullptr, 0, fmt, args...);
- std::string buf(size, 0);
- snprintf(&buf[0], size + 1, fmt, args...);
- return buf;
- }
};
struct ErrorInfo {
diff --git a/src/package.cpp b/src/package.cpp
@@ -91,8 +91,10 @@ Package::Package(const Type type, const string &name, const Category *cat)
{
if(m_name.empty())
throw reapack_error("empty package name");
- else if(m_name.find_first_of("/\\") != string::npos)
- throw reapack_error("invalid package name '%s'", m_name.c_str());
+ else if(m_name.find_first_of("/\\") != string::npos) {
+ throw reapack_error(
+ String::format("invalid package name '%s'", m_name.c_str()));
+ }
}
Package::~Package()
@@ -112,8 +114,10 @@ bool Package::addVersion(const Version *ver)
throw reapack_error("version belongs to another package");
else if(ver->sources().empty())
return false;
- else if(m_versions.count(ver))
- throw reapack_error("duplicate version '%s'", ver->fullName().c_str());
+ else if(m_versions.count(ver)) {
+ throw reapack_error(String::format("duplicate version '%s'",
+ ver->fullName().c_str()));
+ }
m_versions.insert(ver);
diff --git a/src/string.cpp b/src/string.cpp
@@ -0,0 +1,35 @@
+/* ReaPack: Package manager for REAPER
+ * Copyright (C) 2015-2017 Christian Fillion
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "string.hpp"
+
+std::string String::format(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ const int size = vsnprintf(nullptr, 0, fmt, args);
+ va_end(args);
+
+ std::string buf(size, 0);
+
+ va_start(args, fmt);
+ vsnprintf(&buf[0], size + 1, fmt, args);
+ va_end(args);
+
+ return buf;
+}
diff --git a/src/string.hpp b/src/string.hpp
@@ -0,0 +1,30 @@
+/* ReaPack: Package manager for REAPER
+ * Copyright (C) 2015-2017 Christian Fillion
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef REAPACK_STRING_HPP
+#define REAPACK_STRING_HPP
+
+#include <string>
+
+namespace String {
+#ifdef __GNUC__
+ __attribute__((format(printf, 1, 2)))
+#endif
+ std::string format(const char *fmt, ...);
+}
+
+#endif
diff --git a/src/task.cpp b/src/task.cpp
@@ -107,7 +107,8 @@ void InstallTask::commit()
for(const TempPath &paths : m_newFiles) {
if(!FS::rename(paths)) {
- tx()->receipt()->addError({string("Cannot rename to target: ") + FS::lastError(),
+ tx()->receipt()->addError({
+ String::format("Cannot rename to target: %s", FS::lastError()),
paths.target().join()});
// it's a bit late to rollback here as some files might already have been
diff --git a/src/transaction.cpp b/src/transaction.cpp
@@ -169,7 +169,7 @@ IndexPtr Transaction::loadIndex(const Remote &remote)
}
catch(const reapack_error &e) {
m_receipt.addError({
- string("Couldn't load repository: ") + e.what(), remote.name()});
+ String::format("Could not load repository: %s", e.what()), remote.name()});
return nullptr;
}
}
diff --git a/src/version.cpp b/src/version.cpp
@@ -102,7 +102,7 @@ void VersionName::parse(const string &str)
if(first >= 'a' || first >= 'z') {
if(segments.empty()) // got leading letters
- throw reapack_error("invalid version name '%s'", str.c_str());
+ throw reapack_error(String::format("invalid version name '%s'", str.c_str()));
segments.push_back(match);
letters++;
@@ -112,13 +112,13 @@ void VersionName::parse(const string &str)
segments.push_back(boost::lexical_cast<Numeric>(match));
}
catch(const boost::bad_lexical_cast &) {
- throw reapack_error("version segment overflow in '%s'", str.c_str());
+ throw reapack_error(String::format("version segment overflow in '%s'", str.c_str()));
}
}
}
if(segments.empty()) // version doesn't have any numbers
- throw reapack_error("invalid version name '%s'", str.c_str());
+ throw reapack_error(String::format("invalid version name '%s'", str.c_str()));
m_string = str;
swap(m_segments, segments);
diff --git a/test/string.cpp b/test/string.cpp
@@ -0,0 +1,13 @@
+#include "helper.hpp"
+
+#include <string.hpp>
+
+static constexpr const char *M = "[string]";
+
+using namespace std;
+
+TEST_CASE("string format", M) {
+ const string &formatted = String::format("%d%% Hello %s!", 100, "World");
+ CHECK(formatted.size() == 17);
+ REQUIRE(formatted == "100% Hello World!");
+}