commit 04dec7f699800309d334db7230e9d1ef8830c7ec
parent 3be587869587b87555256fb7e0aed4d15bfe076d
Author: cfillion <cfillion@users.noreply.github.com>
Date: Thu, 1 Jun 2017 21:24:03 -0400
api: implement basic code and CompareVersions
Diffstat:
8 files changed, 171 insertions(+), 3 deletions(-)
diff --git a/src/api.cpp b/src/api.cpp
@@ -0,0 +1,96 @@
+/* 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 "api.hpp"
+
+#include <boost/preprocessor.hpp>
+#include <cstdint>
+#include <cstdio>
+
+#include <reaper_plugin_functions.h>
+
+#include "version.hpp"
+
+using namespace std;
+
+#define API_PREFIX "ReaPack_"
+
+APIDef::APIDef(const APIFunc *func)
+ : m_func(func)
+{
+ plugin_register(m_func->cKey, m_func->cImpl);
+ plugin_register(m_func->reascriptKey, m_func->reascriptImpl);
+ plugin_register(m_func->definitionKey, m_func->definition);
+}
+
+APIDef::~APIDef()
+{
+ unregister(m_func->cKey, m_func->cImpl);
+ unregister(m_func->reascriptKey, m_func->reascriptImpl);
+ unregister(m_func->definitionKey, m_func->definition);
+}
+
+void APIDef::unregister(const char *key, void *ptr)
+{
+ char buf[255];
+ snprintf(buf, sizeof(buf), "-%s", key);
+ plugin_register(buf, ptr);
+}
+
+#define ARG_TYPE(arg) BOOST_PP_TUPLE_ELEM(2, 0, arg)
+#define ARG_NAME(arg) BOOST_PP_TUPLE_ELEM(2, 1, arg)
+
+#define ARGS(r, data, i, arg) BOOST_PP_COMMA_IF(i) ARG_TYPE(arg) ARG_NAME(arg)
+#define PARAMS(r, data, i, arg) BOOST_PP_COMMA_IF(i) (ARG_TYPE(arg))(intptr_t)argv[i]
+#define DEFARGS(r, macro, i, arg) \
+ BOOST_PP_IF(i, ",", BOOST_PP_EMPTY()) BOOST_PP_STRINGIZE(macro(arg))
+
+#define DEFAPI(type, name, args, help, ...) \
+ namespace name { \
+ static type cImpl(BOOST_PP_SEQ_FOR_EACH_I(ARGS, _, args)) __VA_ARGS__ \
+ void *reascriptImpl(void **argv, int argc) { \
+ if(argc == BOOST_PP_SEQ_SIZE(args)) \
+ return (void *)(intptr_t)cImpl(BOOST_PP_SEQ_FOR_EACH_I(PARAMS, _, args)); \
+ return nullptr; \
+ } \
+ static const char *definition = #type "\0" \
+ BOOST_PP_SEQ_FOR_EACH_I(DEFARGS, ARG_TYPE, args) "\0" \
+ BOOST_PP_SEQ_FOR_EACH_I(DEFARGS, ARG_NAME, args) "\0" help; \
+ }; \
+ APIFunc API::name = {\
+ "API_" API_PREFIX #name, (void *)&name::cImpl, \
+ "APIvararg_" API_PREFIX #name, (void *)&name::reascriptImpl, \
+ "APIdef_" API_PREFIX #name, (void *)name::definition, \
+ }
+
+DEFAPI(bool, CompareVersions, ((const char*, ver1))((const char*, ver2))
+ ((int*, resultOut))((char*, errorOut))((int, errorOut_sz)),
+ "Compare version numbers. Returns 0 if both versions are equal,"
+ " a positive value if ver1 is higher than ver2"
+ " and a negative value otherwise.",
+{
+ VersionName a, b;
+ string error;
+
+ if(a.tryParse(ver1, &error) && b.tryParse(ver2, &error)) {
+ *resultOut = a.compare(b);
+ return true;
+ }
+
+ snprintf(errorOut, errorOut_sz, "%s", error.c_str());
+ return false;
+});
diff --git a/src/api.hpp b/src/api.hpp
@@ -0,0 +1,47 @@
+/* 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_API_HPP
+#define REAPACK_API_HPP
+
+struct APIFunc {
+ const char *cKey;
+ void *cImpl;
+
+ const char *reascriptKey;
+ void *reascriptImpl;
+
+ const char *definitionKey;
+ void *definition;
+};
+
+class APIDef {
+public:
+ APIDef(const APIFunc *);
+ ~APIDef();
+
+private:
+ void unregister(const char *key, void *ptr);
+
+ const APIFunc *m_func;
+};
+
+namespace API {
+ extern APIFunc CompareVersions;
+};
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "api.hpp"
#include "errors.hpp"
#include "menu.hpp"
#include "reapack.hpp"
@@ -157,6 +158,11 @@ static void setupActions()
reapack->setupAction("REAPACK_ABOUT", bind(&ReaPack::aboutSelf, reapack));
}
+static void setupAPI()
+{
+ reapack->setupAPI(&API::CompareVersions);
+}
+
extern "C" REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(
REAPER_PLUGIN_HINSTANCE instance, reaper_plugin_info_t *rec)
{
@@ -181,6 +187,7 @@ extern "C" REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(
reapack = new ReaPack(instance);
setupActions();
+ setupAPI();
plugin_register("hookcommand", (void *)commandHook);
plugin_register("hookcustommenu", (void *)menuHook);
diff --git a/src/reapack.cpp b/src/reapack.cpp
@@ -18,6 +18,7 @@
#include "reapack.hpp"
#include "about.hpp"
+#include "api.hpp"
#include "browser.hpp"
#include "config.hpp"
#include "download.hpp"
@@ -142,6 +143,11 @@ bool ReaPack::execActions(const int id, const int)
return true;
}
+void ReaPack::setupAPI(const APIFunc *func)
+{
+ m_api.push_back(std::make_unique<APIDef>(func));
+}
+
void ReaPack::synchronizeAll()
{
const vector<Remote> &remotes = m_config->remotes.getEnabled();
diff --git a/src/reapack.hpp b/src/reapack.hpp
@@ -29,12 +29,14 @@
#include <reaper_plugin.h>
class About;
+class APIDef;
class Browser;
class Config;
class Manager;
class Progress;
class Remote;
class Transaction;
+struct APIFunc;
class ReaPack {
public:
@@ -58,6 +60,8 @@ public:
gaccel_register_t *action, const ActionCallback &);
bool execActions(int id, int);
+ void setupAPI(const APIFunc *func);
+
void synchronizeAll();
void setRemoteEnabled(bool enable, const Remote &);
void enable(const Remote &r) { setRemoteEnabled(true, r); }
@@ -82,6 +86,7 @@ private:
void teardownTransaction();
std::map<int, ActionCallback> m_actions;
+ std::vector<std::unique_ptr<APIDef> > m_api;
Config *m_config;
Transaction *m_tx;
diff --git a/src/version.cpp b/src/version.cpp
@@ -126,13 +126,16 @@ void VersionName::parse(const string &str)
m_stable = letters < 1;
}
-bool VersionName::tryParse(const string &str)
+bool VersionName::tryParse(const string &str, string *errorOut)
{
try {
parse(str);
return true;
}
- catch(const reapack_error &) {
+ catch(const reapack_error &err) {
+ if(errorOut)
+ *errorOut = err.what();
+
return false;
}
}
diff --git a/src/version.hpp b/src/version.hpp
@@ -38,7 +38,7 @@ public:
VersionName(const VersionName &);
void parse(const std::string &);
- bool tryParse(const std::string &);
+ bool tryParse(const std::string &, std::string *errorOut = nullptr);
size_t size() const { return m_segments.size(); }
bool isStable() const { return m_stable; }
diff --git a/test/version.cpp b/test/version.cpp
@@ -90,8 +90,12 @@ TEST_CASE("parse version failsafe", M) {
SECTION("invalid") {
REQUIRE_FALSE(ver.tryParse("hello"));
+ string error;
+ REQUIRE_FALSE(ver.tryParse("world", &error));
+
REQUIRE(ver.toString().empty());
REQUIRE(ver.size() == 0);
+ REQUIRE(error == "invalid version name 'world'");
}
}