reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

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:
Asrc/api.cpp | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/api.hpp | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.cpp | 7+++++++
Msrc/reapack.cpp | 6++++++
Msrc/reapack.hpp | 5+++++
Msrc/version.cpp | 7+++++--
Msrc/version.hpp | 2+-
Mtest/version.cpp | 4++++
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'"); } }