init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
|
||||
# Add all the subdirs as projects of the named branch
|
||||
OV_ADD_PROJECTS("APPLICATIONS_DEVELOPER-TOOLS")
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
PROJECT(openvibe-id-generator)
|
||||
|
||||
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
|
||||
SET(PROJECT_VERSION_MINOR ${OV_GLOBAL_VERSION_MINOR})
|
||||
SET(PROJECT_VERSION_PATCH ${OV_GLOBAL_VERSION_PATCH})
|
||||
SET(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.inl)
|
||||
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_FILES})
|
||||
SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${APP_FOLDER})
|
||||
|
||||
# ---------------------------------
|
||||
# Target macros
|
||||
# Defines target operating system, architecture and compiler
|
||||
# ---------------------------------
|
||||
SET_BUILD_PLATFORM()
|
||||
|
||||
# ----------------------
|
||||
# Generate launch script
|
||||
# ----------------------
|
||||
OV_INSTALL_LAUNCH_SCRIPT(SCRIPT_PREFIX "openvibe-id-generator" EXECUTABLE_NAME "${PROJECT_NAME}" PAUSE)
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::default_random_engine rng(rd());
|
||||
std::uniform_int_distribution<size_t> uni(0, std::numeric_limits<size_t>::max() - 1);
|
||||
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
const uint32_t v1 = uni(rng), v2 = uni(rng);
|
||||
std::stringstream ss;
|
||||
ss.fill('0');
|
||||
ss << "(0x" << std::setw(8) << std::hex << v1 << ", 0x" << std::setw(8) << std::hex << v2 << ")";
|
||||
std::cout << "#define OV_ClassId_\t\t\tOpenViBE::CIdentifier" << ss.str() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
#######################################################################
|
||||
# Software License Agreement (AGPL-3 License)
|
||||
#
|
||||
# OpenViBE SDK Test Software
|
||||
# Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
# Copyright (C) Inria, 2015-2017,V1.0
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License version 3,
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
#######################################################################
|
||||
|
||||
PROJECT(openvibe-plugin-inspector)
|
||||
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h)
|
||||
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_FILES})
|
||||
SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${APP_FOLDER})
|
||||
|
||||
INCLUDE("FindOpenViBE")
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
INCLUDE("FindOpenViBEToolkit")
|
||||
INCLUDE("FindOpenViBEModuleSystem")
|
||||
INCLUDE("FindOpenViBEModuleFS")
|
||||
INCLUDE("FindThirdPartyBoost")
|
||||
|
||||
# ---------------------------------
|
||||
# Target macros
|
||||
# Defines target operating system, architecture and compiler
|
||||
# ---------------------------------
|
||||
SET_BUILD_PLATFORM()
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#include "ovpiCPluginObjectDescEnum.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace PluginInspector {
|
||||
|
||||
// Enumerate plugins by iterating over a user defined list of descriptors, used for metaboxes
|
||||
bool CPluginObjectDescEnum::enumeratePluginObjectDesc(std::vector<const Plugins::IPluginObjectDesc*>& pod)
|
||||
{
|
||||
for (auto* plugin : pod) { this->callback(*plugin); }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginObjectDescEnum::enumeratePluginObjectDesc(const CIdentifier& parentClassID)
|
||||
{
|
||||
CIdentifier id;
|
||||
while ((id = m_kernelCtx.getPluginManager().getNextPluginObjectDescIdentifier(id, parentClassID)) != CIdentifier::undefined())
|
||||
{
|
||||
this->callback(*m_kernelCtx.getPluginManager().getPluginObjectDesc(id));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CPluginObjectDescEnum::transform(const std::string& in, const bool removeSlash)
|
||||
{
|
||||
std::string out;
|
||||
bool wasLastASeparator = true;
|
||||
|
||||
for (size_t i = 0; i < in.length(); ++i)
|
||||
{
|
||||
if ((in[i] >= 'a' && in[i] <= 'z') || (in[i] >= 'A' && in[i] <= 'Z') || (in[i] >= '0' && in[i] <= '9') || (!removeSlash && in[i] == '/'))
|
||||
{
|
||||
if (in[i] == '/') { out += "_"; }
|
||||
else
|
||||
{
|
||||
if (wasLastASeparator)
|
||||
{
|
||||
if ('a' <= in[i] && in[i] <= 'z') { out += in[i] + 'A' - 'a'; }
|
||||
else { out += in[i]; }
|
||||
}
|
||||
else { out += in[i]; }
|
||||
}
|
||||
wasLastASeparator = false;
|
||||
}
|
||||
else { wasLastASeparator = true; }
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace PluginInspector
|
||||
} // namespace OpenViBE
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace PluginInspector {
|
||||
class CPluginObjectDescEnum
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CPluginObjectDescEnum(const Kernel::IKernelContext& ctx) : m_kernelCtx(ctx) { }
|
||||
virtual ~CPluginObjectDescEnum() { }
|
||||
|
||||
virtual bool enumeratePluginObjectDesc(std::vector<const Plugins::IPluginObjectDesc*>& pod);
|
||||
virtual bool enumeratePluginObjectDesc(const CIdentifier& parentClassID);
|
||||
|
||||
virtual bool callback(const Plugins::IPluginObjectDesc& pod) = 0;
|
||||
|
||||
static std::string transform(const std::string& in, bool removeSlash = false);
|
||||
|
||||
protected:
|
||||
|
||||
const Kernel::IKernelContext& m_kernelCtx;
|
||||
};
|
||||
} // namespace PluginInspector
|
||||
} // namespace OpenViBE
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
#include "ovpiCPluginObjectDescEnumBoxTemplateGenerator.h"
|
||||
|
||||
#include <system/ovCTime.h>
|
||||
#include <fs/Files.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace PluginInspector {
|
||||
|
||||
static std::map<int, char> indentCharacters = { { 0, '=' }, { 1, '-' }, { 2, '~' }, { 3, '+' } };
|
||||
static std::string generateRstTitle(const std::string& title, const int level)
|
||||
{
|
||||
return title + "\n" + std::string(title.size(), indentCharacters[level]) + "\n";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------------
|
||||
bool CPluginObjectDescEnumBoxTemplateGenerator::initialize()
|
||||
{
|
||||
if (!m_kernelCtx.getScenarioManager().createScenario(m_scenarioID)) { return false; }
|
||||
m_scenario = &m_kernelCtx.getScenarioManager().getScenario(m_scenarioID);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------------
|
||||
bool CPluginObjectDescEnumBoxTemplateGenerator::uninitialize()
|
||||
{
|
||||
if (!m_kernelCtx.getScenarioManager().releaseScenario(m_scenarioID)) { return false; }
|
||||
|
||||
std::ofstream ofBoxIdx;
|
||||
FS::Files::openOFStream(ofBoxIdx, (m_docTemplateDirectory + "/index-boxes.rst").c_str());
|
||||
|
||||
if (!ofBoxIdx.good())
|
||||
{
|
||||
m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "Error while trying to open file [" << (m_docTemplateDirectory + "/index-boxes.rst").c_str() <<
|
||||
"]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
ofBoxIdx << ".. _Doc_BoxAlgorithms:\n\n" << generateRstTitle("Boxes list", 0) << "\nAvailable box algorithms are :\n\n" << generateRstIndex(m_categories) <<
|
||||
" \n";
|
||||
|
||||
if (!m_deprecatedBoxesCategories.empty())
|
||||
{
|
||||
ofBoxIdx << "\n\n" << generateRstTitle("Deprecated boxes list", 0) <<
|
||||
"\nThe following boxes are deprecated, they are hidden in Studio and will be removed soon or later, so you should consider not using them:\n"
|
||||
<< generateRstIndex(m_deprecatedBoxesCategories) << " \n";
|
||||
}
|
||||
|
||||
ofBoxIdx << " \n";
|
||||
ofBoxIdx.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------------
|
||||
bool CPluginObjectDescEnumBoxTemplateGenerator::callback(const Plugins::IPluginObjectDesc& pod)
|
||||
{
|
||||
const std::string fileName = "BoxAlgorithm_" + transform(pod.getName().toASCIIString());
|
||||
CIdentifier boxID;
|
||||
|
||||
if (pod.getCreatedClass() == OVP_ClassId_BoxAlgorithm_Metabox)
|
||||
{
|
||||
// insert a box into the scenario, initialize it from the proxy-descriptor from the metabox loader
|
||||
if (!m_scenario->addBox(boxID, dynamic_cast<const Plugins::IBoxAlgorithmDesc&>(pod), CIdentifier::undefined()))
|
||||
{
|
||||
m_kernelCtx.getLogManager() << Kernel::LogLevel_Warning << "Skipped [" << fileName << "] (could not create corresponding box)\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (!m_scenario->addBox(boxID, pod.getCreatedClassIdentifier(), CIdentifier::undefined()))
|
||||
{
|
||||
m_kernelCtx.getLogManager() << Kernel::LogLevel_Warning << "Skipped [" << fileName << "] (could not create corresponding box)\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Kernel::IBox& box = *m_scenario->getBoxDetails(boxID);
|
||||
|
||||
m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "Working on [" << fileName << "]\n";
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
std::ofstream ofs;
|
||||
FS::Files::openOFStream(ofs, (m_docTemplateDirectory + "/Doc_" + fileName + ".rst-template").c_str());
|
||||
|
||||
if (!ofs.good())
|
||||
{
|
||||
m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "Error while trying to open file ["
|
||||
<< (m_docTemplateDirectory + "/Doc_" + fileName + ".rst-template").c_str()
|
||||
<< "]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
ofs << ".. _Doc_" << fileName << ":\n\n" << generateRstTitle(pod.getName().toASCIIString(), 0)
|
||||
<< "\n.. container:: attribution\n\n :Author:\n " << pod.getAuthorName().toASCIIString() << "\n"
|
||||
<< " :Company:\n " << pod.getAuthorCompanyName().toASCIIString() << "\n\n\n"
|
||||
<< ".. todo:: Write general box description...\n\n\n";
|
||||
|
||||
|
||||
if (box.getInputCount())
|
||||
{
|
||||
ofs << ".. _Doc_" << fileName << "_Inputs:\n\n" << generateRstTitle("Inputs", 1).c_str()
|
||||
<< ".. todo:: Write general input description...\n\n.. csv-table::\n :header: \"Input Name\", \"Stream Type\"\n\n";
|
||||
|
||||
std::vector<CString> inputNames(box.getInputCount());
|
||||
for (size_t i = 0; i < box.getInputCount(); ++i)
|
||||
{
|
||||
CIdentifier typeID;
|
||||
box.getInputName(i, inputNames[i]);
|
||||
box.getInputType(i, typeID);
|
||||
CString typeName = m_kernelCtx.getTypeManager().getTypeName(typeID);
|
||||
|
||||
ofs << " \"" << inputNames[i] << "\", \"" << typeName << "\"\n";
|
||||
}
|
||||
size_t index = 1;
|
||||
for (const auto& name : inputNames)
|
||||
{
|
||||
ofs << "\n.. _Doc_" << fileName << "_Input_" << index << ":\n\n" << generateRstTitle(name.toASCIIString(), 2)
|
||||
<< "\n.. todo:: Write input description...\n\n\n";
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (box.getOutputCount())
|
||||
{
|
||||
ofs << ".. _Doc_" << fileName << "_Outputs:\n\n" << generateRstTitle("Outputs", 1)
|
||||
<< "\n.. todo:: Write general output description...\n\n.. csv-table::\n :header: \"Output Name\", \"Stream Type\"\n\n";
|
||||
|
||||
std::vector<CString> outputNames(box.getOutputCount());
|
||||
for (size_t i = 0; i < box.getOutputCount(); ++i)
|
||||
{
|
||||
CIdentifier typeID;
|
||||
box.getOutputName(i, outputNames[i]);
|
||||
box.getOutputType(i, typeID);
|
||||
CString typeName = m_kernelCtx.getTypeManager().getTypeName(typeID);
|
||||
|
||||
ofs << " \"" << outputNames[i] << "\", \"" << typeName << "\"\n";
|
||||
}
|
||||
size_t index = 1;
|
||||
for (const auto& outputName : outputNames)
|
||||
{
|
||||
ofs << "\n.. _Doc_" << fileName << "_Output_" << index << ":\n\n" << generateRstTitle(outputName.toASCIIString(), 2)
|
||||
<< "\n.. todo:: Write output description...\n\n\n";
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (box.getSettingCount())
|
||||
{
|
||||
ofs << ".. _Doc_" << fileName << "_Settings:\n\n" << generateRstTitle("Settings", 1) << "\n"
|
||||
<< ".. todo:: Write settings general description...\n\n.. csv-table::\n :header: \"Setting Name\", \"Type\", \"Default Value\"\n\n";
|
||||
|
||||
std::vector<CString> settingsNames(box.getSettingCount());
|
||||
for (size_t i = 0; i < box.getSettingCount(); ++i)
|
||||
{
|
||||
CIdentifier typeID;
|
||||
CString defaultValue;
|
||||
box.getSettingName(i, settingsNames[i]);
|
||||
box.getSettingType(i, typeID);
|
||||
box.getSettingDefaultValue(i, defaultValue);
|
||||
CString typeName = m_kernelCtx.getTypeManager().getTypeName(typeID);
|
||||
|
||||
ofs << " \"" << settingsNames[i] << "\", \"" << typeName << "\", \"" << defaultValue << "\"\n";
|
||||
}
|
||||
size_t index = 1;
|
||||
for (const auto& name : settingsNames)
|
||||
{
|
||||
ofs << "\n.. _Doc_" << fileName << "_Setting_" << index << ":\n\n" << generateRstTitle(name.toASCIIString(), 2)
|
||||
<< "\n.. todo:: Write setting description... \n\n\n";
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
ofs << ".. _Doc_" << fileName << "_Examples:\n\n" << generateRstTitle("Examples", 1)
|
||||
<< "\n.. todo:: Write example of use...\n\n\n";
|
||||
|
||||
ofs << ".. _Doc_" << fileName << "_Miscellaneous:\n\n" << generateRstTitle("Miscellaneous", 1)
|
||||
<< "\n.. todo:: Write any miscellaneous information...\n\n\n";
|
||||
|
||||
ofs.close();
|
||||
|
||||
// m_categories is used to generate the list of boxes. Documentation for deprecated boxes
|
||||
// should remain available if needed but not be listed
|
||||
if (m_kernelCtx.getPluginManager().isPluginObjectFlaggedAsDeprecated(box.getAlgorithmClassIdentifier()))
|
||||
{
|
||||
m_deprecatedBoxesCategories.push_back(std::pair<std::string, std::string>(pod.getCategory().toASCIIString(), pod.getName().toASCIIString()));
|
||||
}
|
||||
else { m_categories.push_back(std::pair<std::string, std::string>(pod.getCategory().toASCIIString(), pod.getName().toASCIIString())); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------------
|
||||
std::string CPluginObjectDescEnumBoxTemplateGenerator::generateRstIndex(std::vector<std::pair<std::string, std::string>> categories) const
|
||||
{
|
||||
std::string res;
|
||||
|
||||
std::string lastCategoryName;
|
||||
std::vector<std::string> lastSplittedCategories;
|
||||
std::sort(categories.begin(), categories.end());
|
||||
|
||||
for (auto& category : categories)
|
||||
{
|
||||
std::string categoryName = category.first;
|
||||
std::string name = category.second;
|
||||
|
||||
if (lastCategoryName != categoryName)
|
||||
{
|
||||
std::vector<std::string> splittedCategories;
|
||||
size_t i = size_t(-1);
|
||||
bool isFinished = false;
|
||||
while (!isFinished)
|
||||
{
|
||||
size_t j = categoryName.find('/', i + 1);
|
||||
if (j == std::string::npos)
|
||||
{
|
||||
j = categoryName.length();
|
||||
isFinished = true;
|
||||
}
|
||||
if (j != i + 1)
|
||||
{
|
||||
splittedCategories.push_back(categoryName.substr(i + 1, j - i - 1));
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
auto itLast = lastSplittedCategories.begin();
|
||||
auto it1 = splittedCategories.begin();
|
||||
for (; itLast != lastSplittedCategories.end() && it1 != splittedCategories.end() && *itLast == *it1; ++itLast, ++it1) { }
|
||||
|
||||
for (; it1 != splittedCategories.end(); ++it1)
|
||||
{
|
||||
size_t level = 1;
|
||||
for (auto it2 = splittedCategories.begin(); it2 != it1; ++it2) { level++; }
|
||||
res += "\n\n" + generateRstTitle(*it1, int(level)) + "\n.. toctree::\n :maxdepth: 1\n\n";
|
||||
}
|
||||
|
||||
lastCategoryName = categoryName;
|
||||
lastSplittedCategories = splittedCategories;
|
||||
}
|
||||
|
||||
res += " Doc_BoxAlgorithm_" + transform(name) + "\n";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace PluginInspector
|
||||
} // namespace OpenViBE
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovpiCPluginObjectDescEnum.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace PluginInspector {
|
||||
class CPluginObjectDescEnumBoxTemplateGenerator final : public CPluginObjectDescEnum
|
||||
{
|
||||
public:
|
||||
|
||||
CPluginObjectDescEnumBoxTemplateGenerator(const Kernel::IKernelContext& ctx, const std::string& docTemplateDir)
|
||||
: CPluginObjectDescEnum(ctx), m_docTemplateDirectory(docTemplateDir) {}
|
||||
|
||||
bool callback(const Plugins::IPluginObjectDesc& pod) override;
|
||||
bool initialize();
|
||||
bool uninitialize();
|
||||
|
||||
private:
|
||||
// Return a string that correspond to the indexed categories under rst format
|
||||
std::string generateRstIndex(std::vector<std::pair<std::string, std::string>> categories) const;
|
||||
|
||||
protected:
|
||||
|
||||
std::string m_docTemplateDirectory;
|
||||
std::vector<std::pair<std::string, std::string>> m_categories;
|
||||
std::vector<std::pair<std::string, std::string>> m_deprecatedBoxesCategories;
|
||||
CIdentifier m_scenarioID = CIdentifier::undefined();
|
||||
Kernel::IScenario* m_scenario = nullptr;
|
||||
};
|
||||
} // namespace PluginInspector
|
||||
} // namespace OpenViBE
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
#include "ovpiCPluginObjectDescEnumBoxTemplateGenerator.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include <fs/Files.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
/*
|
||||
USAGE:
|
||||
plugin-inspector <plugin1 plugin2 ...>
|
||||
<--box-doc-directory dir>
|
||||
*/
|
||||
|
||||
std::vector<std::string> pluginFilestoLoad;
|
||||
|
||||
std::string docTemplateDir;
|
||||
bool ignoreMetaboxes = false;
|
||||
std::vector<std::string> metaboxExtensionsToLoad;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
|
||||
{
|
||||
std::cout << "[ USAGE ]\n" << "plugin-inspector <plugin1 plugin2 ...>\n" << " <--box-doc-directory dir>\n";
|
||||
return 0;
|
||||
}
|
||||
std::cout << "Analyze parameter: [" << i << " : " << argv[i] << "]." << std::endl;
|
||||
|
||||
if (strcmp(argv[i], "--ignore-metaboxes") == 0) { ignoreMetaboxes = true; }
|
||||
else if (i < argc && strcmp(argv[i], "--box-doc-directory") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
std::cout << "[ FAILED ] Error while parsing arguments: --box-doc-directory flag found but no path specified afterwards." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
docTemplateDir = argv[i];
|
||||
std::cout << "Templates will be generated in folder: [" << docTemplateDir << "]." << std::endl;
|
||||
}
|
||||
else if (i < argc) { pluginFilestoLoad.push_back(std::string(argv[i])); }
|
||||
}
|
||||
|
||||
OpenViBE::CKernelLoader kernelLoader;
|
||||
|
||||
std::cout << "[ INF ] Created kernel loader, trying to load kernel module" << std::endl;
|
||||
OpenViBE::CString errorMsg;
|
||||
#if defined TARGET_OS_Windows
|
||||
const OpenViBE::CString kernelFile = OpenViBE::Directories::getLibDir() + "/openvibe-kernel.dll";
|
||||
#elif defined TARGET_OS_Linux
|
||||
const OpenViBE::CString kernelFile = OpenViBE::Directories::getLibDir() + "/libopenvibe-kernel.so";
|
||||
#elif defined TARGET_OS_MacOS
|
||||
const OpenViBE::CString kernelFile = OpenViBE::Directories::getLibDir() + "/libopenvibe-kernel.dylib";
|
||||
#endif
|
||||
|
||||
if (!kernelLoader.load(kernelFile, &errorMsg)) { std::cout << "[ FAILED ] Error loading kernel (" << errorMsg << ")" << " from [" << kernelFile << "]\n"; }
|
||||
else
|
||||
{
|
||||
std::cout << "[ INF ] Kernel module loaded, trying to get kernel descriptor" << std::endl;
|
||||
OpenViBE::Kernel::IKernelDesc* kernelDesc = nullptr;
|
||||
kernelLoader.initialize();
|
||||
kernelLoader.getKernelDesc(kernelDesc);
|
||||
if (!kernelDesc) { std::cout << "[ FAILED ] No kernel descriptor" << std::endl; }
|
||||
else
|
||||
{
|
||||
std::cout << "[ INF ] Got kernel descriptor, trying to create kernel" << std::endl;
|
||||
|
||||
OpenViBE::Kernel::IKernelContext* ctx = kernelDesc->createKernel("plugin-inspector", OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
|
||||
if (!ctx) { std::cout << "[ FAILED ] No kernel created by kernel descriptor" << std::endl; }
|
||||
else
|
||||
{
|
||||
ctx->initialize();
|
||||
OpenViBE::Toolkit::initialize(*ctx);
|
||||
|
||||
OpenViBE::Kernel::IConfigurationManager& configurationManager = ctx->getConfigurationManager();
|
||||
|
||||
if (pluginFilestoLoad.empty()) { ctx->getPluginManager().addPluginsFromFiles(configurationManager.expand("${Kernel_Plugins}")); }
|
||||
else
|
||||
{
|
||||
for (const std::string& file : pluginFilestoLoad)
|
||||
{
|
||||
ctx->getPluginManager().addPluginsFromFiles(configurationManager.expand(OpenViBE::CString(file.c_str())));
|
||||
}
|
||||
}
|
||||
|
||||
ctx->getLogManager() << OpenViBE::Kernel::LogLevel_Info << "[ INF ] Generate boxes templates in [" << docTemplateDir << "]\n";
|
||||
|
||||
OpenViBE::PluginInspector::CPluginObjectDescEnumBoxTemplateGenerator boxTemplateGenerator(*ctx, std::string(docTemplateDir));
|
||||
if (!boxTemplateGenerator.initialize())
|
||||
{
|
||||
std::cout << "[ FAILED ] Could not initialize boxTemplateGenerator" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
boxTemplateGenerator.enumeratePluginObjectDesc(OV_ClassId_Plugins_BoxAlgorithmDesc);
|
||||
|
||||
if (!ignoreMetaboxes)
|
||||
{
|
||||
ctx->getLogManager() << OpenViBE::Kernel::LogLevel_Info << "[ INF ] Generate metaboxes templates in [" << docTemplateDir << "]\n";
|
||||
// Do not load the binary metaboxes as they would only be duplicated
|
||||
//ctx->getScenarioManager().unregisterScenarioImporter(OV_ScenarioImportContext_OnLoadMetaboxImport, ".mbb");
|
||||
configurationManager.addOrReplaceConfigurationToken("Kernel_Metabox", "${Path_Data}/metaboxes/");
|
||||
|
||||
ctx->getMetaboxManager().addMetaboxesFromFiles(configurationManager.expand("${Kernel_Metabox}"));
|
||||
|
||||
// Create a list of metabox descriptors from the Map provided by the MetaboxLoader and enumerate all algorithms within
|
||||
std::vector<const OpenViBE::Plugins::IPluginObjectDesc*> metaboxPluginObjectDescriptors;
|
||||
OpenViBE::CIdentifier id;
|
||||
while ((id = ctx->getMetaboxManager().getNextMetaboxObjectDescIdentifier(id)) != OpenViBE::CIdentifier::undefined())
|
||||
{
|
||||
metaboxPluginObjectDescriptors.push_back(ctx->getMetaboxManager().getMetaboxObjectDesc(id));
|
||||
}
|
||||
boxTemplateGenerator.enumeratePluginObjectDesc(metaboxPluginObjectDescriptors);
|
||||
}
|
||||
|
||||
if (!boxTemplateGenerator.uninitialize())
|
||||
{
|
||||
std::cout << "[ FAILED ] Could not uninitialize boxTemplateGenerator" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
ctx->getLogManager() << OpenViBE::Kernel::LogLevel_Info << "Application terminated, releasing allocated objects \n";
|
||||
|
||||
OpenViBE::Toolkit::uninitialize(*ctx);
|
||||
|
||||
kernelDesc->releaseKernel(ctx);
|
||||
}
|
||||
}
|
||||
kernelLoader.uninitialize();
|
||||
kernelLoader.unload();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#######################################################################
|
||||
# Software License Agreement (AGPL-3 License)
|
||||
#
|
||||
# OpenViBE SDK Test Software
|
||||
# Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
# Copyright (C) Inria, 2015-2017,V1.0
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License version 3,
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
#######################################################################
|
||||
|
||||
PROJECT(openvibe-scenario-player)
|
||||
|
||||
# ----------------------
|
||||
# Project variables
|
||||
# ----------------------
|
||||
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
|
||||
SET(PROJECT_VERSION_MINOR ${OV_GLOBAL_VERSION_MINOR})
|
||||
SET(PROJECT_VERSION_PATCH ${OV_GLOBAL_VERSION_PATCH})
|
||||
SET(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
|
||||
# ----------------------
|
||||
# Add executable
|
||||
# ----------------------
|
||||
ADD_DEFINITIONS( -DPROJECT_VERSION="${PROJECT_VERSION}" )
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.hpp)
|
||||
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_FILES})
|
||||
SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${APP_FOLDER})
|
||||
|
||||
# ----------------------
|
||||
# External dependecies
|
||||
# ----------------------
|
||||
|
||||
# To be done after add executable because FindOpenViBEXXX files need a target name
|
||||
INCLUDE("FindOpenViBE")
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
INCLUDE("FindOpenViBEToolkit")
|
||||
INCLUDE("FindOpenViBEModuleSystem")
|
||||
INCLUDE("FindOpenViBEModuleFS")
|
||||
INCLUDE("FindThirdPartyBoost")
|
||||
|
||||
# ---------------------------------
|
||||
# Target macros
|
||||
# Defines target operating system, architecture and compiler
|
||||
# ---------------------------------
|
||||
SET_BUILD_PLATFORM()
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ovspCKernelFacade.h"
|
||||
#include "ovspCCommand.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
EPlayerReturnCodes SInitCmd::execute(CKernelFacade& kernelFacade) const
|
||||
{
|
||||
std::cout << "About to execute:" << std::endl << *this << std::endl;
|
||||
return kernelFacade.initialize();
|
||||
}
|
||||
|
||||
void SInitCmd::doPrint(std::ostream& os) const
|
||||
{
|
||||
os << "command name: InitCommand" << std::endl;
|
||||
os << "Benchmark: " << (this->benchmark ? std::to_string(this->benchmark.get()) : "not set") << std::endl;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes SLoadKernelCmd::execute(CKernelFacade& kernelFacade) const
|
||||
{
|
||||
std::cout << "About to execute:" << std::endl << *this << std::endl;
|
||||
// default config file is an empty one so it is not problem to give it directly as param
|
||||
return kernelFacade.loadKernel(*this);
|
||||
}
|
||||
|
||||
void SLoadKernelCmd::doPrint(std::ostream& os) const
|
||||
{
|
||||
os << "command name: LoadKernelCommand" << std::endl;
|
||||
os << "ConfigurationFile: " << (this->configFile ? this->configFile.get() : "not set") << std::endl;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes SLoadScenarioCmd::execute(CKernelFacade& kernelFacade) const
|
||||
{
|
||||
std::cout << "About to execute:" << std::endl << *this << std::endl;
|
||||
|
||||
if (!this->scenarioName || !this->scenarioFile)
|
||||
{
|
||||
std::cerr << "Missing required arguments for command" << std::endl;
|
||||
return EPlayerReturnCodes::MissingMandatoryArgument;
|
||||
}
|
||||
|
||||
return kernelFacade.loadScenario(*this);
|
||||
}
|
||||
|
||||
void SLoadScenarioCmd::doPrint(std::ostream& os) const
|
||||
{
|
||||
os << "command name: LoadScenarioCommand" << std::endl;
|
||||
os << "ScenarioName: " << (this->scenarioName ? this->scenarioName.get() : "not set") << std::endl;
|
||||
os << "ScenarioFile: " << (this->scenarioFile ? this->scenarioFile.get() : "not set") << std::endl;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes SUpdateScenarioCmd::execute(CKernelFacade& kernelFacade) const
|
||||
{
|
||||
std::cout << "About to execute:" << std::endl << *this << std::endl;
|
||||
|
||||
if (!this->scenarioName || !this->scenarioFile)
|
||||
{
|
||||
std::cerr << "Missing required arguments for command" << std::endl;
|
||||
return EPlayerReturnCodes::MissingMandatoryArgument;
|
||||
}
|
||||
|
||||
return kernelFacade.updateScenario(*this);
|
||||
}
|
||||
|
||||
void SUpdateScenarioCmd::doPrint(std::ostream& os) const
|
||||
{
|
||||
os << "command name: UpdateScenarioCommand" << std::endl;
|
||||
os << "ScenarioName: " << (this->scenarioName ? this->scenarioName.get() : "not set") << std::endl;
|
||||
os << "ScenarioFile: " << (this->scenarioFile ? this->scenarioFile.get() : "not set") << std::endl;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes SResetCmd::execute(CKernelFacade& /*kernelFacade*/) const
|
||||
{
|
||||
// to be implemented
|
||||
std::cout << "About to execute:" << std::endl << *this << std::endl << "Not implemented yet" << std::endl;
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
void SResetCmd::doPrint(std::ostream& os) const { os << "command name: ResetCommand" << std::endl; }
|
||||
|
||||
EPlayerReturnCodes SRunScenarioCmd::execute(CKernelFacade& kernelFacade) const
|
||||
{
|
||||
std::cout << "About to execute:" << std::endl << *this << std::endl;
|
||||
if (!this->scenarioList)
|
||||
{
|
||||
std::cerr << "Missing required arguments for command: ScenarioList" << std::endl;
|
||||
return EPlayerReturnCodes::MissingMandatoryArgument;
|
||||
}
|
||||
return kernelFacade.runScenarioList(*this);
|
||||
}
|
||||
|
||||
void SRunScenarioCmd::doPrint(std::ostream& os) const
|
||||
{
|
||||
os << "command name: SRunScenarioCmd" << std::endl;
|
||||
|
||||
os << "ScenarioList:";
|
||||
if (this->scenarioList) { for (auto& scenario : this->scenarioList.get()) { os << " " << scenario; } }
|
||||
else { os << " not set"; }
|
||||
os << std::endl;
|
||||
|
||||
os << "PlayMode: ";
|
||||
if (this->playMode)
|
||||
{
|
||||
const std::string modeAsString = (this->playMode == EPlayerPlayMode::Fastfoward) ? "fastforward" : "standard";
|
||||
os << modeAsString;
|
||||
}
|
||||
else { os << "not set"; }
|
||||
os << std::endl;
|
||||
|
||||
os << "MaximumExecutionTime: " << (this->maximumExecutionTime ? std::to_string(this->maximumExecutionTime.get()) : "not set") << std::endl;
|
||||
|
||||
os << "TokenList:";
|
||||
if (this->tokenList) { for (auto& token : this->tokenList.get()) { os << " (" << token.first << "," << token.second << ")"; } }
|
||||
else { os << " not set"; }
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes SSetupScenarioCmd::execute(CKernelFacade& kernelFacade) const
|
||||
{
|
||||
std::cout << "About to execute:" << std::endl << *this << std::endl;
|
||||
if (!this->scenarioName)
|
||||
{
|
||||
std::cerr << "Missing required arguments for command" << std::endl;
|
||||
return EPlayerReturnCodes::MissingMandatoryArgument;
|
||||
}
|
||||
return kernelFacade.setupScenario(*this);
|
||||
}
|
||||
|
||||
void SSetupScenarioCmd::doPrint(std::ostream& os) const
|
||||
{
|
||||
os << "command name: SSetupScenarioCmd" << std::endl;
|
||||
os << "ScenarioName: " << (this->scenarioName ? this->scenarioName.get() : "not set") << std::endl;
|
||||
os << "TokenList:";
|
||||
if (this->tokenList) { for (auto& token : this->tokenList.get()) { os << " (" << token.first << "," << token.second << ")"; } }
|
||||
else { os << " not set"; }
|
||||
os << std::endl;
|
||||
}
|
||||
} // namespace OpenViBE
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovspICommand.h"
|
||||
#include <boost/optional.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace OpenViBE {
|
||||
/**
|
||||
* \struct SInitCmd
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Command that drives the initialization of the tool
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* InitCommand class contains the following properties:
|
||||
* - Benchmark: Flag to enable benchmark on execute command (optional).
|
||||
*
|
||||
*/
|
||||
struct SInitCmd final : SCommand
|
||||
{
|
||||
// List of properties
|
||||
boost::optional<bool> benchmark;
|
||||
|
||||
EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const override;
|
||||
|
||||
protected:
|
||||
void doPrint(std::ostream& os) const override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \struct SLoadKernelCmd
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Command that drives kernel loading
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* LoadKernelCommand contains the following properties:
|
||||
* - ConfigurationFile: Path to kernel configuration file (optional)
|
||||
* .
|
||||
*
|
||||
*/
|
||||
struct SLoadKernelCmd final : SCommand
|
||||
{
|
||||
// List of properties
|
||||
boost::optional<std::string> configFile;
|
||||
|
||||
EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const override;
|
||||
|
||||
protected:
|
||||
|
||||
void doPrint(std::ostream& os) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct SLoadScenarioCmd
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Command that drives scenario loading
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* LoadScenarioCommand contains the following properties:
|
||||
* - ScenarioFile: Path to xml scenario file (mandatory)
|
||||
* - ScenarioName: Name of the scenario (mandatory)
|
||||
* .
|
||||
*
|
||||
*/
|
||||
struct SLoadScenarioCmd final : SCommand
|
||||
{
|
||||
// List of properties
|
||||
boost::optional<std::string> scenarioFile;
|
||||
boost::optional<std::string> scenarioName;
|
||||
|
||||
EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const override;
|
||||
|
||||
protected:
|
||||
|
||||
void doPrint(std::ostream& os) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct SUpdateScenarioCmd
|
||||
* \author criou (INRIA)
|
||||
* \date 2018-04-16
|
||||
* \brief Command that drives scenario update and export
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* UpdateScenarioCommand contains the following properties:
|
||||
* - ScenarioFile: Path to xml scenario file (mandatory)
|
||||
* .
|
||||
*
|
||||
*/
|
||||
struct SUpdateScenarioCmd final : SCommand
|
||||
{
|
||||
// List of properties
|
||||
boost::optional<std::string> scenarioFile;
|
||||
boost::optional<std::string> scenarioName;
|
||||
|
||||
EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const override;
|
||||
|
||||
protected:
|
||||
|
||||
void doPrint(std::ostream& os) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct SResetCmd
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Command that drives tool reset to its initial state
|
||||
* \ingroup ScenarioPlayer
|
||||
*/
|
||||
struct SResetCmd final : SCommand
|
||||
{
|
||||
EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const override;
|
||||
|
||||
protected:
|
||||
|
||||
void doPrint(std::ostream& os) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct SRunScenarioCmd
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Command that drives the execution of a list of scenarios
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* SRunScenarioCmd contains the following properties:
|
||||
* - ScenarioList: Names of scenario that must be executed (mandatory)
|
||||
* - PlayMode: 0 for standard, 1 for fastforward (optional)
|
||||
* - MaximumExecutionTime: Scenarios playing execution time limit (optional)
|
||||
* - TokenList: List of global (token,value) pairs (optional)
|
||||
* .
|
||||
*
|
||||
*/
|
||||
struct SRunScenarioCmd final : SCommand
|
||||
{
|
||||
using Token = std::pair<std::string, std::string>;
|
||||
|
||||
// List of properties
|
||||
boost::optional<std::vector<std::string>> scenarioList;
|
||||
boost::optional<EPlayerPlayMode> playMode;
|
||||
boost::optional<double> maximumExecutionTime;
|
||||
boost::optional<std::vector<Token>> tokenList;
|
||||
|
||||
EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const override;
|
||||
|
||||
protected:
|
||||
|
||||
void doPrint(std::ostream& os) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct SSetupScenarioCmd
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Command that drives the setup of a scenario
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* SSetupScenarioCmd contains the following properties:
|
||||
* - ScenarioName: name of the scenario to setup (mandatory)
|
||||
* - TokenList: List of scenario specific tokens (optional)
|
||||
* .
|
||||
*
|
||||
* The token list overwrites the previous token list if the command was already
|
||||
* called on the same scenario (note that an empty token list is allowed).
|
||||
*
|
||||
*/
|
||||
struct SSetupScenarioCmd final : SCommand
|
||||
{
|
||||
using Token = std::pair<std::string, std::string>;
|
||||
|
||||
// List of properties
|
||||
boost::optional<std::string> scenarioName;
|
||||
boost::optional<std::vector<Token>> tokenList;
|
||||
|
||||
|
||||
EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const override;
|
||||
|
||||
protected:
|
||||
|
||||
void doPrint(std::ostream& os) const override;
|
||||
};
|
||||
} // namespace OpenViBE
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ovspCCommand.h"
|
||||
#include "ovspCCommandFileParser.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
|
||||
// should be moved in a utility class/file
|
||||
std::string CommandFileParser::trim(const std::string& str)
|
||||
{
|
||||
// remove leading and trailing space
|
||||
// no use of regex here cause it might be too slow
|
||||
auto begin = str.find_first_not_of(" \t"), end = str.find_last_not_of(" \t");
|
||||
if (begin == std::string::npos) { begin = 0; }
|
||||
if (end == std::string::npos) { end = str.size() - 1; }
|
||||
return str.substr(begin, end - begin + 1);
|
||||
}
|
||||
|
||||
// should be moved in a utility class/file
|
||||
std::pair<std::string, std::string> CommandFileParser::tokenize(const std::string& str)
|
||||
{
|
||||
// given a string of type "token : value", return a pair of (token,value)
|
||||
// split method is not used because only the first delimiter is of interest
|
||||
const auto split = str.find_first_of(':');
|
||||
|
||||
if (split == std::string::npos) { throw std::runtime_error("Impossible to convert " + str + " to token/value pair"); }
|
||||
|
||||
auto token = trim(str.substr(0, split));
|
||||
auto val = trim(str.substr(split + 1, str.size() - split - 1));
|
||||
|
||||
return std::make_pair(token, val);
|
||||
}
|
||||
|
||||
// should be moved in a utility class/file
|
||||
std::vector<std::string> CommandFileParser::split(const std::string& str, const char delimiter)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
size_t currentIdx = 0;
|
||||
size_t delimiterIdx = str.find(delimiter);
|
||||
|
||||
auto trimmed = trim(str.substr(currentIdx, delimiterIdx));
|
||||
if (!trimmed.empty()) { vec.push_back(trimmed); }
|
||||
|
||||
while (delimiterIdx != std::string::npos)
|
||||
{
|
||||
// abc,cde,fgh
|
||||
// ^ -> current index points to the first element after a match
|
||||
// ^ -> delimiter index points to next match
|
||||
currentIdx = delimiterIdx + 1;
|
||||
delimiterIdx = str.find(delimiter, currentIdx);
|
||||
|
||||
trimmed = trim(str.substr(currentIdx, delimiterIdx - currentIdx));
|
||||
|
||||
if (!trimmed.empty()) { vec.push_back(trimmed); }
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
// should be moved in a utility class/file
|
||||
bool CommandFileParser::toBool(const std::string& str)
|
||||
{
|
||||
// try to keep same behavior as stoi or stol
|
||||
|
||||
std::string lowerStr;
|
||||
lowerStr.reserve(str.size());
|
||||
std::transform(str.begin(), str.end(), lowerStr.begin(), tolower);
|
||||
|
||||
bool result;
|
||||
if (str == "false" || str == "0") { result = false; }
|
||||
else if (str == "true" || str == "1") { result = true; }
|
||||
else { throw std::runtime_error("Impossible to convert " + str + " to bool"); }
|
||||
return result;
|
||||
}
|
||||
|
||||
// should be moved in a utility class/file
|
||||
// input is expected to be trimmed (by a call to tolenize for example)
|
||||
std::vector<std::string> CommandFileParser::toList(const std::string& str)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
// {token1, token2, token3 ...} pattern expected
|
||||
if (str.size() >= 3 && str[0] == '{' && str[str.size() - 1] == '}') { vec = split(str.substr(1, str.length() - 2), ','); }
|
||||
else { throw std::runtime_error("Impossible to convert " + str + " to list"); }
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
// should be moved in a utility class/file
|
||||
// part of this function duplicates code from ProgramOptions.hpp
|
||||
std::vector<CommandFileParser::Token> CommandFileParser::toTokenList(const std::string& str)
|
||||
{
|
||||
std::vector<Token> vec;
|
||||
|
||||
for (auto& rawToken : toList(str))
|
||||
{
|
||||
// rawToken is expected to be trimmed
|
||||
|
||||
const auto split = rawToken.find_first_of(':');
|
||||
const auto size = rawToken.size();
|
||||
|
||||
// (a:b) pattern expected
|
||||
// minimal regex std::regex("\\(.+:.+\\)")
|
||||
if (!(size >= 5 && rawToken[0] == '(' && rawToken[size - 1] == ')') || split == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Failed to parse token pair from value: " + rawToken);
|
||||
}
|
||||
|
||||
Token token;
|
||||
token.first = trim(rawToken.substr(1, split - 1));
|
||||
|
||||
// magic 2 numbers is because substr takes a length as second parameter
|
||||
// 2 = remove the last ) + account for the first one
|
||||
token.second = trim(rawToken.substr(split + 1, size - split - 2));
|
||||
|
||||
vec.push_back(token);
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void CommandFileParser::initialize()
|
||||
{
|
||||
// using a callback mechanism allows us to implement the core parse() method
|
||||
// very easily (no need to put some if/else blocks everywhere depending on which command is encountered)
|
||||
m_callbacks["Init"] = std::bind(&CommandFileParser::initCommandCb, this, std::placeholders::_1);
|
||||
m_callbacks["Reset"] = std::bind(&CommandFileParser::resetCommandCb, this, std::placeholders::_1);
|
||||
m_callbacks["LoadKernel"] = std::bind(&CommandFileParser::loadKernelCommandCb, this, std::placeholders::_1);
|
||||
m_callbacks["LoadScenario"] = std::bind(&CommandFileParser::loadScenarioCommandCb, this, std::placeholders::_1);
|
||||
m_callbacks["SetupScenario"] = std::bind(&CommandFileParser::setupScenarioCommandCb, this, std::placeholders::_1);
|
||||
m_callbacks["RunScenario"] = std::bind(&CommandFileParser::runScenarioCommandCb, this, std::placeholders::_1);
|
||||
}
|
||||
|
||||
void CommandFileParser::uninitialize()
|
||||
{
|
||||
m_callbacks.clear();
|
||||
m_cmdList.clear();
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::parse()
|
||||
{
|
||||
std::ifstream fileStream(m_cmdFile);
|
||||
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
std::cerr << "ERROR: impossible to open file at location: " << m_cmdFile << std::endl;
|
||||
return EPlayerReturnCodes::OpeningFileFailure;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
bool isFillingSection{ false };
|
||||
std::vector<std::string> sectionContent;
|
||||
std::string sectionTag;
|
||||
|
||||
while (std::getline(fileStream, line))
|
||||
{
|
||||
auto trimmedLine = trim(line);
|
||||
const auto size = trimmedLine.size();
|
||||
|
||||
// [a] pattern expected
|
||||
// minimal regex std::regex("^(?!\\#)\\[.+\\])")
|
||||
if (size >= 3 && trimmedLine[0] == '['
|
||||
&& trimmedLine[size - 1] == ']')
|
||||
{
|
||||
if (isFillingSection) // flush the section that was beeing filled
|
||||
{
|
||||
const auto errorCode = this->flush(sectionTag, sectionContent);
|
||||
if (errorCode != EPlayerReturnCodes::Success) { return errorCode; }
|
||||
}
|
||||
|
||||
// use of regex to be confident on tag structure
|
||||
// magic 2 numbers is because substr takes length as second parameter
|
||||
// 2 = remove the last ] + account for the first one
|
||||
sectionTag = trimmedLine.substr(1, size - 2);
|
||||
|
||||
if (m_callbacks.find(sectionTag) == m_callbacks.end())
|
||||
{
|
||||
std::cerr << "ERROR: Unknown command = " << sectionTag << std::endl;
|
||||
return EPlayerReturnCodes::ParsingCommandFailure;
|
||||
}
|
||||
|
||||
isFillingSection = true;
|
||||
sectionContent.clear();
|
||||
}
|
||||
else { sectionContent.push_back(trimmedLine); }
|
||||
}
|
||||
|
||||
if (isFillingSection)
|
||||
{
|
||||
const auto errorCode = this->flush(sectionTag, sectionContent);
|
||||
if (errorCode != EPlayerReturnCodes::Success) { return errorCode; }
|
||||
}
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::flush(const std::string& sectionTag, const std::vector<std::string>& sectionContent)
|
||||
{
|
||||
try // try block here as some conversions are made with the stl in the callback and might throw
|
||||
{
|
||||
const auto returnCode = m_callbacks[sectionTag](sectionContent);
|
||||
if (returnCode != EPlayerReturnCodes::Success) { return returnCode; }
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: Caught exception while parsing command = " << sectionTag << std::endl;
|
||||
std::cerr << "ERROR: Exception: " << e.what() << std::endl;
|
||||
return EPlayerReturnCodes::ParsingCommandFailure;
|
||||
}
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::initCommandCb(const std::vector<std::string>& sectionContent)
|
||||
{
|
||||
std::shared_ptr<SInitCmd> command = std::make_shared<SInitCmd>();
|
||||
|
||||
for (const auto& line : sectionContent)
|
||||
{
|
||||
// lines are expected to be trimmed
|
||||
// a:b pattern expected
|
||||
// minimal regex std::regex("^(?!\\#).+:.+")
|
||||
if (!line.empty() && line[0] != '#')
|
||||
{
|
||||
auto param = tokenize(line);
|
||||
|
||||
if (param.first == "Benchmark") { command->benchmark = toBool(param.second); }
|
||||
else { std::cout << "WARNING: Unknown parameter for Init command: " << param.first << std::endl; }
|
||||
}
|
||||
}
|
||||
m_cmdList.push_back(command);
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::resetCommandCb(const std::vector<std::string>& /*sectionContent*/)
|
||||
{
|
||||
const std::shared_ptr<SResetCmd> command = std::make_shared<SResetCmd>();
|
||||
m_cmdList.push_back(command);
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::loadKernelCommandCb(const std::vector<std::string>& sectionContent)
|
||||
{
|
||||
std::shared_ptr<SLoadKernelCmd> command = std::make_shared<SLoadKernelCmd>();
|
||||
|
||||
// cf. initCommandCb
|
||||
for (const auto& line : sectionContent)
|
||||
{
|
||||
if (!line.empty() && line[0] != '#')
|
||||
{
|
||||
auto param = tokenize(line);
|
||||
if (param.first == "ConfigurationFile") { command->configFile = param.second; }
|
||||
else { std::cout << "WARNING: Unknown parameter for LoadKernel command: " << param.first << std::endl; }
|
||||
}
|
||||
}
|
||||
m_cmdList.push_back(command);
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::loadScenarioCommandCb(const std::vector<std::string>& sectionContent)
|
||||
{
|
||||
std::shared_ptr<SLoadScenarioCmd> command = std::make_shared<SLoadScenarioCmd>();
|
||||
|
||||
// cf. initCommandCb
|
||||
for (const auto& line : sectionContent)
|
||||
{
|
||||
if (!line.empty() && line[0] != '#')
|
||||
{
|
||||
auto param = tokenize(line);
|
||||
|
||||
if (param.first == "ScenarioName") { command->scenarioName = param.second; }
|
||||
else if (param.first == "ScenarioFile") { command->scenarioFile = param.second; }
|
||||
else { std::cout << "WARNING: Unknown parameter for LoadScenario command: " << param.first << std::endl; }
|
||||
}
|
||||
}
|
||||
m_cmdList.push_back(command);
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::setupScenarioCommandCb(const std::vector<std::string>& sectionContent)
|
||||
{
|
||||
std::shared_ptr<SSetupScenarioCmd> command = std::make_shared<SSetupScenarioCmd>();
|
||||
|
||||
// cf. initCommandCb
|
||||
for (const auto& line : sectionContent)
|
||||
{
|
||||
if (!line.empty() && line[0] != '#')
|
||||
{
|
||||
auto param = tokenize(line);
|
||||
|
||||
if (param.first == "ScenarioName") { command->scenarioName = param.second; }
|
||||
else if (param.first == "TokenList") { command->tokenList = toTokenList(param.second); }
|
||||
else { std::cout << "WARNING: Unknown parameter for SetupScenario command: " << param.first << std::endl; }
|
||||
}
|
||||
}
|
||||
m_cmdList.push_back(command);
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CommandFileParser::runScenarioCommandCb(const std::vector<std::string>& sectionContent)
|
||||
{
|
||||
std::shared_ptr<SRunScenarioCmd> command = std::make_shared<SRunScenarioCmd>();
|
||||
|
||||
// cf. initCommandCb
|
||||
for (const auto& line : sectionContent)
|
||||
{
|
||||
if (!line.empty() && line[0] != '#')
|
||||
{
|
||||
auto param = tokenize(line);
|
||||
|
||||
if (param.first == "ScenarioList") { command->scenarioList = toList(param.second); }
|
||||
else if (param.first == "PlayMode") { command->playMode = EPlayerPlayMode(std::stoi(param.second)); }
|
||||
else if (param.first == "MaximumExecutionTime") { command->maximumExecutionTime = std::stod(param.second); }
|
||||
else if (param.first == "TokenList") { command->tokenList = (toTokenList(param.second)); }
|
||||
else { std::cout << "WARNING: Unknown parameter for RunScenario command: " << param.first << std::endl; }
|
||||
}
|
||||
}
|
||||
m_cmdList.push_back(command);
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
} // namespace OpenViBE
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
#include "ovspICommandParser.h"
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
/**
|
||||
* \class CommandFileParser
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-27
|
||||
* \brief Parser implementation that parses command a file
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* The current implementation retrieves the list of commands from a file.
|
||||
*
|
||||
* Input file format requirements:
|
||||
* - Command names are defined within brackets [InitCommand] on a single line
|
||||
* - Each command parameter is defined on a single line below the command name:
|
||||
* + Single value parameters are defined as: parameterName: value
|
||||
* + Simple list parameters are defined as: parameterName: {val1,val2,...}
|
||||
* + Token list parameters are defined as: parameterName: { (token1:val1),(token2:val2) } (no ',' authorized in (token, value) pair)
|
||||
* .
|
||||
* .
|
||||
*
|
||||
* \todo The implementation uses a lot of string utility functions that need more
|
||||
* testing
|
||||
*
|
||||
* \note Use of regex would simplify the implementation but boost::regex is not header-only and std::regex not implemented in gcc 4.8
|
||||
*
|
||||
*/
|
||||
class CommandFileParser final : public ICommandParser
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
*
|
||||
* \brief Constructor
|
||||
* \param[in] file path to the command file
|
||||
*
|
||||
*/
|
||||
explicit CommandFileParser(const std::string& file) : m_cmdFile(file) { }
|
||||
|
||||
void initialize() override;
|
||||
void uninitialize() override;
|
||||
|
||||
std::vector<std::shared_ptr<SCommand>> getCommandList() const override { return m_cmdList; }
|
||||
|
||||
EPlayerReturnCodes parse() override;
|
||||
|
||||
private:
|
||||
|
||||
using CallbackType = std::function<EPlayerReturnCodes(std::vector<std::string>)>;
|
||||
using Token = std::pair<std::string, std::string>;
|
||||
|
||||
static std::string trim(const std::string& str);
|
||||
static std::pair<std::string, std::string> tokenize(const std::string& str);
|
||||
static std::vector<std::string> split(const std::string& str, char delimiter);
|
||||
static bool toBool(const std::string& str);
|
||||
static std::vector<std::string> toList(const std::string& str);
|
||||
static std::vector<Token> toTokenList(const std::string& str);
|
||||
|
||||
EPlayerReturnCodes flush(const std::string& sectionTag, const std::vector<std::string>& sectionContent);
|
||||
|
||||
EPlayerReturnCodes initCommandCb(const std::vector<std::string>& sectionContent);
|
||||
EPlayerReturnCodes resetCommandCb(const std::vector<std::string>& sectionContent);
|
||||
EPlayerReturnCodes loadKernelCommandCb(const std::vector<std::string>& sectionContent);
|
||||
EPlayerReturnCodes loadScenarioCommandCb(const std::vector<std::string>& sectionContent);
|
||||
EPlayerReturnCodes setupScenarioCommandCb(const std::vector<std::string>& sectionContent);
|
||||
EPlayerReturnCodes runScenarioCommandCb(const std::vector<std::string>& sectionContent);
|
||||
|
||||
std::string m_cmdFile;
|
||||
std::vector<std::shared_ptr<SCommand>> m_cmdList;
|
||||
std::map<std::string, CallbackType> m_callbacks;
|
||||
};
|
||||
} // namespace OpenViBE
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ovspCCommand.h"
|
||||
#include "ovspCCommandLineOptionParser.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
CommandLineOptionParser::CommandLineOptionParser(ProgramOptionParser& parser) : m_parser(parser) { }
|
||||
|
||||
void CommandLineOptionParser::initialize() { } // nothing to do
|
||||
void CommandLineOptionParser::uninitialize() { m_cmdList.clear(); }
|
||||
|
||||
std::vector<std::shared_ptr<SCommand>> CommandLineOptionParser::getCommandList() const { return m_cmdList; }
|
||||
|
||||
EPlayerReturnCodes CommandLineOptionParser::parse()
|
||||
{
|
||||
// parsing consists of building a straightfoward command workflow according to command-line
|
||||
// options.
|
||||
|
||||
// commands have to be pushed in the right order
|
||||
|
||||
// choose a dumb name for the scenario
|
||||
std::string scenarioName = "express-scenario";
|
||||
|
||||
// an init command is always needed
|
||||
m_cmdList.push_back(std::make_shared<SInitCmd>());
|
||||
|
||||
|
||||
// workflow must at least load the kernel
|
||||
std::shared_ptr<SLoadKernelCmd> kernelCmd = std::make_shared<SLoadKernelCmd>();
|
||||
|
||||
if (m_parser.hasOption("config-file")) // optional
|
||||
{
|
||||
kernelCmd->configFile = m_parser.getOptionValue<std::string>("config-file");
|
||||
}
|
||||
|
||||
m_cmdList.push_back(kernelCmd);
|
||||
|
||||
// scenario loading is a mandatory step
|
||||
std::shared_ptr<SLoadScenarioCmd> scenarioCmd = std::make_shared<SLoadScenarioCmd>();
|
||||
|
||||
if (m_parser.hasOption("scenario-file")) // mandatory option
|
||||
{
|
||||
scenarioCmd->scenarioFile = m_parser.getOptionValue<std::string>("scenario-file");
|
||||
|
||||
// set dumb name as it used to recognize scenario in the application
|
||||
scenarioCmd->scenarioName = scenarioName;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: mandatory option 'scenario-file' not set" << std::endl;
|
||||
return EPlayerReturnCodes::MissingMandatoryArgument;
|
||||
}
|
||||
|
||||
m_cmdList.push_back(scenarioCmd);
|
||||
|
||||
|
||||
// scenario update option
|
||||
std::shared_ptr<SUpdateScenarioCmd> updateScenarioCmd = std::make_shared<SUpdateScenarioCmd>();
|
||||
|
||||
if (m_parser.hasOption("updated-scenario-file"))
|
||||
{
|
||||
// do not play scenario, just update it.
|
||||
updateScenarioCmd->scenarioFile = m_parser.getOptionValue<std::string>("updated-scenario-file");
|
||||
|
||||
// set dumb name as it used to recognize scenario in the application
|
||||
updateScenarioCmd->scenarioName = scenarioName;
|
||||
|
||||
m_cmdList.push_back(updateScenarioCmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if some scenario setup information has been set
|
||||
if (m_parser.hasOption("ds"))
|
||||
{
|
||||
std::shared_ptr<SSetupScenarioCmd> setupCmd = std::make_shared<SSetupScenarioCmd>();
|
||||
setupCmd->scenarioName = scenarioName;
|
||||
setupCmd->tokenList = m_parser.getOptionValue<std::vector<SSetupScenarioCmd::Token>>("ds");
|
||||
|
||||
m_cmdList.push_back(setupCmd);
|
||||
}
|
||||
|
||||
// last command in the workflow is the run command
|
||||
std::shared_ptr<SRunScenarioCmd> runCmd = std::make_shared<SRunScenarioCmd>();
|
||||
runCmd->scenarioList = std::vector<std::string>{ scenarioName };
|
||||
|
||||
if (m_parser.hasOption("play-mode"))
|
||||
{
|
||||
const auto playMode = m_parser.getOptionValue<std::string>("play-mode");
|
||||
|
||||
if (playMode != "ff" && playMode != "std")
|
||||
{
|
||||
std::cerr << "ERROR: option 'play-mode' must be ff or std" << std::endl;
|
||||
return EPlayerReturnCodes::BadArg;
|
||||
}
|
||||
|
||||
// permissive code here
|
||||
// any other entry than ff leads to standard mode...
|
||||
runCmd->playMode = ((playMode == "ff") ? EPlayerPlayMode::Fastfoward : EPlayerPlayMode::Standard);
|
||||
}
|
||||
|
||||
if (m_parser.hasOption("max-time")) { runCmd->maximumExecutionTime = m_parser.getOptionValue<double>("max-time"); }
|
||||
if (m_parser.hasOption("dg")) { runCmd->tokenList = m_parser.getOptionValue<std::vector<SSetupScenarioCmd::Token>>("dg"); }
|
||||
|
||||
m_cmdList.push_back(runCmd);
|
||||
}
|
||||
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
} // namespace OpenViBE
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
#include "ovspICommandParser.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
/**
|
||||
* \class CommandLineOptionParser
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-27
|
||||
* \brief Parser implementation that parses command from command-line arguments
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* The current implementation retrieves the options from a ProgramOptions parser and
|
||||
* simply builds the commands from the parsed options.
|
||||
*
|
||||
*/
|
||||
class CommandLineOptionParser final : public ICommandParser
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
*
|
||||
* \brief Constructor
|
||||
* \param[in] parser Specific instantiation of ProgramOptions parser
|
||||
*
|
||||
*/
|
||||
explicit CommandLineOptionParser(ProgramOptionParser& parser);
|
||||
|
||||
void initialize() override;
|
||||
void uninitialize() override;
|
||||
|
||||
std::vector<std::shared_ptr<SCommand>> getCommandList() const override;
|
||||
|
||||
EPlayerReturnCodes parse() override;
|
||||
|
||||
private:
|
||||
|
||||
ProgramOptionParser& m_parser;
|
||||
std::vector<std::shared_ptr<SCommand>> m_cmdList;
|
||||
};
|
||||
} // namespace OpenViBE
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ovspCCommand.h"
|
||||
#include "ovsp_base.h"
|
||||
#include "ovspCKernelFacade.h"
|
||||
|
||||
#include <system/ovCTime.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <limits>
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenViBE {
|
||||
|
||||
using TokenList = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
static void setConfigTokens(Kernel::IConfigurationManager& configsManager, const TokenList& tokens)
|
||||
{
|
||||
for (const auto& token : tokens) { configsManager.addOrReplaceConfigurationToken(token.first.c_str(), token.second.c_str()); }
|
||||
}
|
||||
|
||||
struct CKernelFacade::SKernelFacadeImpl
|
||||
{
|
||||
CKernelLoader loader;
|
||||
Kernel::IKernelContext* ctx = nullptr;
|
||||
std::map<std::string, CIdentifier> scenarios;
|
||||
std::map<std::string, TokenList> scenarioTokens;
|
||||
};
|
||||
|
||||
CKernelFacade::CKernelFacade() : m_impl(new SKernelFacadeImpl()) { }
|
||||
|
||||
// The destructor is needed in the .cpp file to implement pimpl idiom
|
||||
// with unique_ptr. This is due to the fact that Kernel facade dtor
|
||||
// has to call unique_ptr<KernelFacadeImpl> deleter function that calls the detete function
|
||||
// on KernelFacadeImpl. Therefore it needs to know KernelFacadeImpl implementation.
|
||||
CKernelFacade::~CKernelFacade()
|
||||
{
|
||||
this->unloadKernel();
|
||||
uninitialize();
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CKernelFacade::loadKernel(const SLoadKernelCmd& command) const
|
||||
{
|
||||
if (m_impl->ctx)
|
||||
{
|
||||
std::cout << "WARNING: The kernel is already loaded" << std::endl;
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
const CString kernelFile = Directories::getLibDir() + "/openvibe-kernel.dll";
|
||||
#elif defined TARGET_OS_Linux
|
||||
const CString kernelFile = Directories::getLibDir() + "/libopenvibe-kernel.so";
|
||||
#elif defined TARGET_OS_MacOS
|
||||
const CString kernelFile = Directories::getLibDir() + "/libopenvibe-kernel.dylib";
|
||||
#endif
|
||||
|
||||
CKernelLoader& kernelLoader = m_impl->loader;
|
||||
CString error;
|
||||
|
||||
if (!kernelLoader.load(kernelFile, &error))
|
||||
{
|
||||
std::cerr << "ERROR: impossible to load kernel from file located at: " << kernelFile << std::endl;
|
||||
return EPlayerReturnCodes::KernelLoadingFailure;
|
||||
}
|
||||
|
||||
kernelLoader.initialize();
|
||||
|
||||
Kernel::IKernelDesc* kernelDesc = nullptr;
|
||||
kernelLoader.getKernelDesc(kernelDesc);
|
||||
|
||||
if (!kernelDesc)
|
||||
{
|
||||
std::cerr << "ERROR: impossible to retrieve kernel descriptor " << std::endl;
|
||||
return EPlayerReturnCodes::KernelInvalidDesc;
|
||||
}
|
||||
|
||||
CString configFile;
|
||||
|
||||
if (command.configFile && !command.configFile.get().empty()) { configFile = command.configFile.get().c_str(); }
|
||||
else { configFile = CString(Directories::getDataDir() + "/kernel/openvibe.conf"); }
|
||||
|
||||
|
||||
Kernel::IKernelContext* ctx = kernelDesc->createKernel("scenario-player", configFile);
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
std::cerr << "ERROR: impossible to create kernel context " << std::endl;
|
||||
return EPlayerReturnCodes::KernelInvalidDesc;
|
||||
}
|
||||
|
||||
ctx->initialize();
|
||||
m_impl->ctx = ctx;
|
||||
Toolkit::initialize(*ctx);
|
||||
|
||||
Kernel::IConfigurationManager& configurationManager = ctx->getConfigurationManager();
|
||||
ctx->getPluginManager().addPluginsFromFiles(configurationManager.expand("${Kernel_Plugins}"));
|
||||
ctx->getMetaboxManager().addMetaboxesFromFiles(configurationManager.expand("${Kernel_Metabox}"));
|
||||
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CKernelFacade::unloadKernel() const
|
||||
{
|
||||
if (m_impl->ctx)
|
||||
{
|
||||
// not releasing the scenario before releasing the kernel
|
||||
// causes a segfault on linux
|
||||
auto& scenarioManager = m_impl->ctx->getScenarioManager();
|
||||
for (auto& scenarioPair : m_impl->scenarios) { scenarioManager.releaseScenario(scenarioPair.second); }
|
||||
|
||||
|
||||
Toolkit::uninitialize(*m_impl->ctx);
|
||||
// m_impl->ctx->uninitialize();
|
||||
Kernel::IKernelDesc* kernelDesc = nullptr;
|
||||
m_impl->loader.getKernelDesc(kernelDesc);
|
||||
kernelDesc->releaseKernel(m_impl->ctx);
|
||||
m_impl->ctx = nullptr;
|
||||
}
|
||||
|
||||
m_impl->loader.uninitialize();
|
||||
m_impl->loader.unload();
|
||||
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CKernelFacade::loadScenario(const SLoadScenarioCmd& command) const
|
||||
{
|
||||
assert(command.scenarioFile && command.scenarioName);
|
||||
|
||||
if (!m_impl->ctx)
|
||||
{
|
||||
std::cerr << "ERROR: Kernel is not loaded" << std::endl;
|
||||
return EPlayerReturnCodes::KernelInternalFailure;
|
||||
}
|
||||
|
||||
const std::string scenarioFile = command.scenarioFile.get();
|
||||
const std::string scenarioName = command.scenarioName.get();
|
||||
|
||||
CIdentifier scenarioID;
|
||||
auto& scenarioManager = m_impl->ctx->getScenarioManager();
|
||||
|
||||
if (!scenarioManager.importScenarioFromFile(scenarioID, scenarioFile.c_str(), OVP_GD_ClassId_Algorithm_XMLScenarioImporter))
|
||||
{
|
||||
std::cerr << "ERROR: failed to create scenario " << std::endl;
|
||||
return EPlayerReturnCodes::KernelInternalFailure;
|
||||
}
|
||||
|
||||
scenarioManager.getScenario(scenarioID).addAttribute(OV_AttributeId_ScenarioFilename, scenarioFile.c_str());
|
||||
|
||||
const auto it = m_impl->scenarios.find(scenarioName);
|
||||
if (it != m_impl->scenarios.end()) { scenarioManager.releaseScenario(it->second); }
|
||||
|
||||
m_impl->scenarios[scenarioName] = scenarioID;
|
||||
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CKernelFacade::updateScenario(const SUpdateScenarioCmd& command) const
|
||||
{
|
||||
assert(command.scenarioFile && command.scenarioName);
|
||||
|
||||
auto& scenarioManager = m_impl->ctx->getScenarioManager();
|
||||
|
||||
const auto scenarioName = command.scenarioName.get();
|
||||
const auto scenarioFile = command.scenarioFile.get();
|
||||
|
||||
if (m_impl->scenarios.find(scenarioName) == m_impl->scenarios.end())
|
||||
{
|
||||
std::cerr << "ERROR: Trying to update a not loaded scenario " << scenarioName << std::endl;
|
||||
return EPlayerReturnCodes::ScenarioNotLoaded;
|
||||
}
|
||||
|
||||
auto& scenario = scenarioManager.getScenario(m_impl->scenarios[scenarioName]);
|
||||
|
||||
// check for boxes to be updated
|
||||
// scenario.checkBoxesRequiringUpdate();
|
||||
|
||||
// update boxes to be updated
|
||||
CIdentifier* listID = nullptr;
|
||||
size_t elemCount = 0;
|
||||
scenario.getOutdatedBoxIdentifierList(&listID, &elemCount);
|
||||
for (size_t i = 0; i < elemCount; ++i) { scenario.updateBox(listID[i]); }
|
||||
|
||||
// export scenario to the destination file
|
||||
if (!scenarioManager.exportScenarioToFile(scenarioFile.c_str(), m_impl->scenarios[scenarioName], OVP_GD_ClassId_Algorithm_XMLScenarioExporter))
|
||||
{
|
||||
std::cerr << "ERROR: failed to create scenario " << std::endl;
|
||||
return EPlayerReturnCodes::KernelInternalFailure;
|
||||
}
|
||||
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CKernelFacade::setupScenario(const SSetupScenarioCmd& command) const
|
||||
{
|
||||
if (!m_impl->ctx)
|
||||
{
|
||||
std::cerr << "ERROR: Kernel is not loaded" << std::endl;
|
||||
return EPlayerReturnCodes::KernelInternalFailure;
|
||||
}
|
||||
|
||||
if (!command.scenarioName)
|
||||
{
|
||||
std::cerr << "ERROR: Missing scenario name for setup" << std::endl;
|
||||
return EPlayerReturnCodes::KernelInternalFailure;
|
||||
}
|
||||
|
||||
const auto name = command.scenarioName.get();
|
||||
|
||||
if (m_impl->scenarios.find(name) == m_impl->scenarios.end())
|
||||
{
|
||||
std::cerr << "ERROR: Trying to configure not loaded scenario " << name << std::endl;
|
||||
return EPlayerReturnCodes::ScenarioNotLoaded;
|
||||
}
|
||||
|
||||
// token list is just stored at this step for further use at runtime
|
||||
// current token list overwrites the previous one
|
||||
if (command.tokenList) { m_impl->scenarioTokens[name] = command.tokenList.get(); }
|
||||
|
||||
return EPlayerReturnCodes::Success;
|
||||
}
|
||||
|
||||
EPlayerReturnCodes CKernelFacade::runScenarioList(const SRunScenarioCmd& command) const
|
||||
{
|
||||
assert(command.scenarioList);
|
||||
|
||||
if (!m_impl->ctx)
|
||||
{
|
||||
std::cerr << "ERROR: Kernel is not loaded" << std::endl;
|
||||
return EPlayerReturnCodes::KernelInternalFailure;
|
||||
}
|
||||
|
||||
auto scenarios = command.scenarioList.get();
|
||||
|
||||
// use of returnCode to store error and achive an RAII-like
|
||||
// behavior by releasing all players at the end
|
||||
EPlayerReturnCodes returnCode = EPlayerReturnCodes::Success;
|
||||
|
||||
// set up global token
|
||||
if (command.tokenList) { setConfigTokens(m_impl->ctx->getConfigurationManager(), command.tokenList.get()); }
|
||||
|
||||
auto& playerManager = m_impl->ctx->getPlayerManager();
|
||||
|
||||
// Keep 2 different containers because identifier information is
|
||||
// not relevant during the performance sensitive loop task.
|
||||
// This might be premature optimization...
|
||||
std::vector<Kernel::IPlayer*> players;
|
||||
std::vector<CIdentifier> playerIDs;
|
||||
|
||||
// attach players to scenario
|
||||
for (auto& pair : m_impl->scenarios)
|
||||
{
|
||||
auto name = pair.first;
|
||||
if (std::find(scenarios.begin(), scenarios.end(), name) == scenarios.end()) { continue; } // not in the list of scenario to run
|
||||
|
||||
CIdentifier id;
|
||||
if (!playerManager.createPlayer(id) || id == CIdentifier::undefined())
|
||||
{
|
||||
std::cerr << "ERROR: impossible to create player" << std::endl;
|
||||
returnCode = EPlayerReturnCodes::KernelInternalFailure;
|
||||
break;
|
||||
}
|
||||
|
||||
Kernel::IPlayer* player = &playerManager.getPlayer(id);
|
||||
|
||||
// player identifier is pushed here to ensure a correct cleanup event if player initialization fails
|
||||
playerIDs.push_back(id);
|
||||
|
||||
CNameValuePairList configTokens;
|
||||
for (auto& token : m_impl->scenarioTokens[name]) { configTokens.setValue(token.first.c_str(), token.second.c_str()); }
|
||||
|
||||
// Scenario attachment with setup of local token
|
||||
if (!player->setScenario(pair.second, &configTokens))
|
||||
{
|
||||
std::cerr << "ERROR: impossible to set player scenario " << name << std::endl;
|
||||
returnCode = EPlayerReturnCodes::KernelInternalFailure;
|
||||
break;
|
||||
}
|
||||
|
||||
if (player->initialize() == Kernel::EPlayerReturnCodes::Success)
|
||||
{
|
||||
if (command.playMode && command.playMode.get() == EPlayerPlayMode::Fastfoward) { player->forward(); }
|
||||
else { player->play(); }
|
||||
|
||||
players.push_back(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: impossible to initialize player for scenario " << name << std::endl;
|
||||
returnCode = EPlayerReturnCodes::KernelInternalFailure;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (returnCode == EPlayerReturnCodes::Success)
|
||||
{
|
||||
// loop until timeout
|
||||
const uint64_t startTime = System::Time::zgetTime();
|
||||
uint64_t lastLoopTime = startTime;
|
||||
|
||||
// cannot directly feed secondsToTime with parameters.m_MaximumExecutionTime
|
||||
// because it could overflow
|
||||
const double boundedMaxExecutionTimeInS = CTime::max().toSeconds();
|
||||
|
||||
uint64_t maxExecutionTimeInFixedPoint;
|
||||
if (command.maximumExecutionTime && command.maximumExecutionTime.get() > 0 && command.maximumExecutionTime.get() < boundedMaxExecutionTimeInS)
|
||||
{
|
||||
maxExecutionTimeInFixedPoint = CTime(double(command.maximumExecutionTime.get())).time();
|
||||
}
|
||||
else { maxExecutionTimeInFixedPoint = std::numeric_limits<uint64_t>::max(); }
|
||||
|
||||
bool allStopped{ false };
|
||||
while (!allStopped) // negative condition here because it is easier to reason about it
|
||||
{
|
||||
const uint64_t currentTime = System::Time::zgetTime();
|
||||
allStopped = true;
|
||||
for (auto* p : players)
|
||||
{
|
||||
if (p->getStatus() != Kernel::EPlayerStatus::Stop)
|
||||
{
|
||||
if (!p->loop(currentTime - lastLoopTime, maxExecutionTimeInFixedPoint)) { returnCode = EPlayerReturnCodes::KernelInternalFailure; }
|
||||
}
|
||||
|
||||
if (p->getCurrentSimulatedTime() >= maxExecutionTimeInFixedPoint) { p->stop(); }
|
||||
|
||||
allStopped &= (p->getStatus() == Kernel::EPlayerStatus::Stop);
|
||||
}
|
||||
|
||||
lastLoopTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
// release players
|
||||
for (auto& id : playerIDs)
|
||||
{
|
||||
playerManager.getPlayer(id).uninitialize();
|
||||
playerManager.releasePlayer(id);
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
} // namespace OpenViBE
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
#include <memory>
|
||||
|
||||
namespace OpenViBE {
|
||||
struct SInitCmd;
|
||||
struct SResetCmd;
|
||||
struct SLoadKernelCmd;
|
||||
struct SLoadScenarioCmd;
|
||||
struct SUpdateScenarioCmd;
|
||||
struct SSetupScenarioCmd;
|
||||
struct SRunScenarioCmd;
|
||||
|
||||
/**
|
||||
* \class CKernelFacade
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Wrapper class used to access Kernel features
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* This class is one-to-many interface used as a central point
|
||||
* to access a subset of Kernel features.
|
||||
*
|
||||
*/
|
||||
class CKernelFacade final
|
||||
{
|
||||
public:
|
||||
|
||||
CKernelFacade();
|
||||
~CKernelFacade();
|
||||
|
||||
/**
|
||||
* \brief Initialize session parameters
|
||||
*/
|
||||
static EPlayerReturnCodes initialize() { return EPlayerReturnCodes::Success; }
|
||||
|
||||
/**
|
||||
* \brief Reset session parameters
|
||||
*/
|
||||
static EPlayerReturnCodes uninitialize() { return EPlayerReturnCodes::Success; }
|
||||
|
||||
/**
|
||||
* \brief Load kernel
|
||||
* \param[in] command command containing all mandatory properties
|
||||
*/
|
||||
EPlayerReturnCodes loadKernel(const SLoadKernelCmd& command) const;
|
||||
|
||||
/**
|
||||
* \brief Unload kernel
|
||||
*/
|
||||
EPlayerReturnCodes unloadKernel() const;
|
||||
|
||||
/**
|
||||
* \brief Load scenario
|
||||
* \param[in] command command containing all mandatory properties
|
||||
*/
|
||||
EPlayerReturnCodes loadScenario(const SLoadScenarioCmd& command) const;
|
||||
|
||||
/**
|
||||
* \brief Update scenario
|
||||
* \param[in] command command containing all mandatory properties
|
||||
*/
|
||||
EPlayerReturnCodes updateScenario(const SUpdateScenarioCmd& command) const;
|
||||
|
||||
/**
|
||||
* \brief Configure scenario
|
||||
* \param[in] command command containing all mandatory properties
|
||||
*/
|
||||
EPlayerReturnCodes setupScenario(const SSetupScenarioCmd& command) const;
|
||||
|
||||
/**
|
||||
* \brief Run one or multiple scenarios
|
||||
* \param[in] command command containing all mandatory properties
|
||||
*/
|
||||
EPlayerReturnCodes runScenarioList(const SRunScenarioCmd& command) const;
|
||||
|
||||
private:
|
||||
|
||||
// disable copy and assignment because it is not meant to used
|
||||
// as a value class event if it is not inheritable
|
||||
CKernelFacade(const CKernelFacade&) = delete;
|
||||
CKernelFacade& operator=(const CKernelFacade&) = delete;
|
||||
|
||||
struct SKernelFacadeImpl;
|
||||
std::unique_ptr<SKernelFacadeImpl> m_impl;
|
||||
};
|
||||
} // namespace OpenViBE
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
class CKernelFacade;
|
||||
|
||||
/**
|
||||
* \struct SCommand
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Base abstract struct for commands
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* A command is an object that encapsulates all necessary information to perform an action later one.
|
||||
* Typically, a command implementation should contain an implementation of CommandInterface interface,
|
||||
* and a list of properties.
|
||||
*
|
||||
*/
|
||||
struct SCommand
|
||||
{
|
||||
SCommand() = default;
|
||||
virtual ~SCommand() = default;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const SCommand& cmd);
|
||||
|
||||
/**
|
||||
* \brief Execute the command
|
||||
* \param[in] kernelFacade the kernel facade that gives access to kernel features
|
||||
*/
|
||||
virtual EPlayerReturnCodes execute(CKernelFacade& kernelFacade) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
// use of the non-virtual interface pattern to implement printing in the class hierarchy
|
||||
virtual void doPrint(std::ostream& os) const = 0;
|
||||
|
||||
private:
|
||||
|
||||
// disable copy and assignment because it is not meant to used
|
||||
// as a value class
|
||||
SCommand(const SCommand&) = delete;
|
||||
SCommand& operator=(const SCommand&) = delete;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const SCommand& cmd)
|
||||
{
|
||||
cmd.doPrint(os);
|
||||
return os;
|
||||
}
|
||||
} // namespace OpenViBE
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace OpenViBE {
|
||||
struct SCommand;
|
||||
|
||||
/**
|
||||
* \class ICommandParser
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-27
|
||||
* \brief Base abstract class for command parser
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* Command parsers aim at parsing a list of commands from a specific input.
|
||||
*
|
||||
*/
|
||||
class ICommandParser
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~ICommandParser() = default;
|
||||
ICommandParser() = default;
|
||||
|
||||
/**
|
||||
* \brief Initialize parser
|
||||
*
|
||||
*/
|
||||
virtual void initialize() = 0;
|
||||
|
||||
/**
|
||||
* \brief Unitialize parser
|
||||
*
|
||||
*/
|
||||
virtual void uninitialize() = 0;
|
||||
|
||||
/**
|
||||
* \brief Retrieve the list of commands
|
||||
* \pre This method should be called after the parse() method
|
||||
*
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<SCommand>> getCommandList() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Retrieve the list of commands
|
||||
* \pre This method should be called after the initialize() method
|
||||
*
|
||||
*/
|
||||
virtual EPlayerReturnCodes parse() = 0;
|
||||
|
||||
private:
|
||||
|
||||
// disable copy and assignment because it is not meant to used
|
||||
// as a value class
|
||||
ICommandParser(const ICommandParser&) = delete;
|
||||
ICommandParser& operator=(const ICommandParser&) = delete;
|
||||
};
|
||||
} // namespace OpenViBE
|
||||
+461
@@ -0,0 +1,461 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
#include <boost/variant.hpp>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace OpenViBE {
|
||||
/**
|
||||
* \struct SProgramOptionsTraits
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-26
|
||||
* \brief Helper class for ProgramOptions type checking
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* This class provides aliases to types currently handled by ProgramOptions class
|
||||
* as well as type checking meta-programming features.
|
||||
*
|
||||
*/
|
||||
struct SProgramOptionsTraits
|
||||
{
|
||||
// add a new type here (type must be default constructible)
|
||||
// and add the corresponding callback in ProgramOptions
|
||||
|
||||
// types handled by ProgramOptions
|
||||
using TokenPair = std::pair<std::string, std::string>;
|
||||
using String = std::string;
|
||||
using Integer = int;
|
||||
using Float = double;
|
||||
|
||||
using StringList = std::vector<std::string>;
|
||||
using IntegerList = std::vector<int>;
|
||||
using FloatList = std::vector<double>;
|
||||
using TokenPairList = std::vector<TokenPair>;
|
||||
};
|
||||
|
||||
namespace ProgramOptionsUtils {
|
||||
// template meta-programming features
|
||||
|
||||
/* Base type that represents a true value at compile-time */
|
||||
struct STrueType
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
/* Base type that represents a false value at compile-time */
|
||||
struct SFalseType
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
/* SIsCompliant is used to statically check if a type is compliant with the handled types */
|
||||
template <typename T>
|
||||
struct SIsCompliant : SFalseType { };
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::TokenPair> : STrueType {};
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::TokenPairList> : STrueType {};
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::String> : STrueType {};
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::StringList> : STrueType {};
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::Integer> : STrueType {};
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::IntegerList> : STrueType {};
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::Float> : STrueType {};
|
||||
|
||||
/* Specialization of the template for compliant types */
|
||||
template <>
|
||||
struct SIsCompliant<SProgramOptionsTraits::FloatList> : STrueType {};
|
||||
|
||||
/* SIsSignatureCompliant is used to statically checked a list of type is compliant with handled type */
|
||||
template <typename... TList>
|
||||
struct SIsSignatureCompliant;
|
||||
|
||||
/* Specialization for empty list */
|
||||
template <>
|
||||
struct SIsSignatureCompliant<> : STrueType {};
|
||||
|
||||
/* Specialization for non-empty list */
|
||||
template <typename THead, typename... TTail>
|
||||
struct SIsSignatureCompliant<THead, TTail...> :
|
||||
std::conditional<SIsCompliant<THead>::value, SIsSignatureCompliant<TTail...>, SFalseType>::type { };
|
||||
|
||||
/* SIsIn is used to statically check if a type T is in a list of types TList*/
|
||||
template <typename T, typename... TList>
|
||||
struct SIsIn; // interface
|
||||
|
||||
/* Specialization for empty list */
|
||||
template <typename T>
|
||||
struct SIsIn<T> : SFalseType {};
|
||||
|
||||
/* Specialization for list where 1st element is a match */
|
||||
template <typename T, typename... TTail>
|
||||
struct SIsIn<T, T, TTail...> : STrueType {};
|
||||
|
||||
/* Specialization for list of many elements */
|
||||
template <typename T, typename THead, typename... TTail>
|
||||
struct SIsIn<T, THead, TTail...> : SIsIn<T, TTail...> {};
|
||||
|
||||
/* SHasDuplicate is used to statically check if a list of types has duplicates*/
|
||||
template <typename... TList>
|
||||
struct SHasDuplicate;
|
||||
|
||||
/* Specialization for empty list */
|
||||
template <>
|
||||
struct SHasDuplicate<> : SFalseType {};
|
||||
|
||||
/* Specialization for 1-element list */
|
||||
template <typename T>
|
||||
struct SHasDuplicate<T> : SFalseType {};
|
||||
|
||||
/* Specialization for list of many elements */
|
||||
template <typename THead, typename... TTail>
|
||||
struct SHasDuplicate<THead, TTail...> : std::conditional<SIsIn<THead, TTail...>::value, STrueType, SHasDuplicate<TTail...>>::type { };
|
||||
} // namespace ProgramOptionsUtils
|
||||
|
||||
/**
|
||||
* \class ProgramOptions
|
||||
* \author cgarraud (INRIA)
|
||||
* \date 2016-01-25
|
||||
* \brief Command-line options parser
|
||||
* \ingroup ScenarioPlayer
|
||||
*
|
||||
* This class is a basic class used to parse program options.
|
||||
* Input format requirements:
|
||||
* - Option prefix must be '-' or '--' e.g. cmd -help or --help
|
||||
* - Option value assignment must be set with '=': e.g. cmd -config=myfile.txt
|
||||
* - Option value that consists of pair are set with (): e.g. cmd -newToken=(key,value)
|
||||
* .
|
||||
*
|
||||
* Template parameters are the list of option types that can be handled by the class.
|
||||
* This list of options must comply to types defined in ProgramOptionsTrait.\n
|
||||
*
|
||||
* Parsing options occurs in 2 steps:
|
||||
* - Populating the list of possible options with simple options (e.g. --help) and value options (e.g. --option=value)
|
||||
* - Parsing options from command line
|
||||
* .
|
||||
*
|
||||
* \todo The parser has only be tested for the player use. It needs more in-depth testing
|
||||
* to be used in another context. Moreover, it should be extended to accept any type.
|
||||
*
|
||||
* \note The implementation is trivial. Prefer the use of robust and fully featured
|
||||
* boost program_options compiled library if possible.
|
||||
*
|
||||
*/
|
||||
template <typename TFirst, typename... TTypes>
|
||||
class ProgramOptions final
|
||||
{
|
||||
public:
|
||||
|
||||
// static assert are used to raise understandable errors at compile time
|
||||
static_assert(!ProgramOptionsUtils::SHasDuplicate<TFirst, TTypes...>::value, "Duplicates in the type list");
|
||||
static_assert(ProgramOptionsUtils::SIsSignatureCompliant<TFirst, TTypes...>::value, "TTypes not handled by ProgramOptions");
|
||||
|
||||
/**
|
||||
* Struct used to store used-defined option parameters.
|
||||
*/
|
||||
struct SOptionDesc // using a struct allows more extensibility than method parameters
|
||||
{
|
||||
/** Option shortname (e.g. h for help) */
|
||||
std::string shortName;
|
||||
/** Option description used for printing option list */
|
||||
std::string desc;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Add global description to the list of options
|
||||
* \param[in] desc the global description in printable format
|
||||
*
|
||||
* The global description is used as additional printable documentation
|
||||
* when printOptionsDesc() is called.
|
||||
*
|
||||
*/
|
||||
void setGlobalDesc(const std::string& desc);
|
||||
|
||||
/**
|
||||
* \brief Add a simple option to the internal dictionary
|
||||
* \param[in] name the option name
|
||||
* \param[in] optionDesc the option description
|
||||
*
|
||||
* Simple options are option withou value (e.g. --help or --version)
|
||||
*
|
||||
*/
|
||||
void addSimpleOption(const std::string& name, const SOptionDesc& optionDesc);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Add a value option to the internal dictionary
|
||||
* \param[in] name the option name
|
||||
* \param[in] optionDesc the option description
|
||||
*
|
||||
* Template paramter T: The type of the option to be added
|
||||
*/
|
||||
template <typename T>
|
||||
void addValueOption(const std::string& name, const SOptionDesc& optionDesc);
|
||||
|
||||
/**
|
||||
* \brief Parse command line options
|
||||
* \pre addSimpleOption and addValueOption must be called to populate options dictionary
|
||||
* \param[in] argc number of arguments
|
||||
* \param[in] argv pointer to the list of arguments
|
||||
* \return: false if an error occurred during parsing, true otherwise
|
||||
*/
|
||||
bool parse(int argc, char** argv);
|
||||
|
||||
/**
|
||||
* \brief Check if an option was parsed or not
|
||||
* \pre Must be called after parse()
|
||||
* \param[in] name the option name
|
||||
* \return: true if the option was parsed, false otherwise
|
||||
*/
|
||||
bool hasOption(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* \brief Get option value
|
||||
* \pre hasOption() should be called to ensure the option is available
|
||||
* \param[in] name the option name
|
||||
* \return the option value (will be the default value if the option was not parsed)
|
||||
*
|
||||
* Template paramter T: the type of the option to retrieve (must match the type used to set
|
||||
* the option with addValueOption())
|
||||
*/
|
||||
template <typename T>
|
||||
T getOptionValue(const std::string& name) const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief print all option descriptions
|
||||
*/
|
||||
void printOptionsDesc() const;
|
||||
|
||||
private:
|
||||
|
||||
// The visitor allows us to apply the correct parsing
|
||||
// for any type (see boost::variant documentation for more details).
|
||||
// Presently, it is pretty ugly. This should be refactored for
|
||||
// as there is a lot of behavorial redundancy.
|
||||
class OptionVisitor : public boost::static_visitor<>
|
||||
{
|
||||
public:
|
||||
|
||||
OptionVisitor(std::string& value) : m_value(value) { }
|
||||
|
||||
void operator()(SProgramOptionsTraits::Integer& operand) const { operand = std::stoi(m_value); }
|
||||
void operator()(SProgramOptionsTraits::Float& operand) const { operand = std::stod(m_value); }
|
||||
void operator()(SProgramOptionsTraits::String& operand) const { operand = m_value; }
|
||||
void operator()(SProgramOptionsTraits::TokenPair& operand) const { operand = this->parsePair(m_value); }
|
||||
void operator()(SProgramOptionsTraits::IntegerList& operand) const { operand.push_back(std::stoi(m_value)); }
|
||||
void operator()(SProgramOptionsTraits::FloatList& operand) const { operand.push_back(std::stod(m_value)); }
|
||||
void operator()(SProgramOptionsTraits::StringList& operand) const { operand.push_back(m_value); }
|
||||
void operator()(SProgramOptionsTraits::TokenPairList& operand) const { operand.push_back(this->parsePair(m_value)); }
|
||||
|
||||
private:
|
||||
|
||||
static SProgramOptionsTraits::TokenPair parsePair(const std::string& str);
|
||||
|
||||
std::string& m_value;
|
||||
};
|
||||
|
||||
using OptionValue = boost::variant<TFirst, TTypes...>;
|
||||
|
||||
// the pair contais a boolean to quickly know if an option
|
||||
// is a simple option or a value option
|
||||
using FullOptionDesc = std::pair<bool, SOptionDesc>;
|
||||
|
||||
std::string m_globalDesc;
|
||||
std::map<std::string, FullOptionDesc> m_descs;
|
||||
std::map<std::string, OptionValue> m_values;
|
||||
std::vector<std::string> m_options;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////
|
||||
/////// Definition ProgramOptions /////////
|
||||
///////////////////////////////////////////
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
void ProgramOptions<TFirst, TTypes...>::setGlobalDesc(const std::string& desc) { m_globalDesc = desc; }
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
void ProgramOptions<TFirst, TTypes...>::addSimpleOption(const std::string& name, const SOptionDesc& optionDesc)
|
||||
{
|
||||
m_descs[name] = std::make_pair(true, optionDesc);
|
||||
}
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
template <typename T>
|
||||
void ProgramOptions<TFirst, TTypes...>::addValueOption(const std::string& name, const SOptionDesc& optionDesc)
|
||||
{
|
||||
m_descs[name] = std::make_pair(false, optionDesc);
|
||||
|
||||
T defaultValue{}; // with this implementation, only default constructible type can be added
|
||||
m_values[name] = defaultValue;
|
||||
}
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
bool ProgramOptions<TFirst, TTypes...>::hasOption(const std::string& name) const
|
||||
{
|
||||
return std::find(m_options.begin(), m_options.end(), name) != m_options.end();
|
||||
}
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
template <typename T>
|
||||
T ProgramOptions<TFirst, TTypes...>::getOptionValue(const std::string& name) const
|
||||
{
|
||||
T value{};
|
||||
|
||||
try { value = boost::get<T>(m_values.at(name)); }
|
||||
catch (const std::exception& e) { std::cerr << "ERROR: Caught exception during option value retrieval: " << e.what() << std::endl; }
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
bool ProgramOptions<TFirst, TTypes...>::parse(const int argc, char** argv)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
#if defined TARGET_OS_Windows
|
||||
int nArg;
|
||||
LPWSTR* argListUtf16 = CommandLineToArgvW(GetCommandLineW(), &nArg);
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
||||
for (int i = 0; i < nArg; ++i) { args.push_back(converter.to_bytes(argListUtf16[i])); }
|
||||
#else
|
||||
args = std::vector<std::string>(argv, argv + argc);
|
||||
#endif
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
std::string arg = args[i];
|
||||
const auto argSplit = arg.find_first_of('='); // = is the separator for value option
|
||||
std::string key;
|
||||
|
||||
if (argSplit == std::string::npos) { key = arg; } // simple option
|
||||
else { key = arg.substr(0, argSplit); } // value option
|
||||
|
||||
// first check if the key exists
|
||||
auto keyMatch = std::find_if(m_descs.begin(), m_descs.end(), [&](const std::pair<std::string, FullOptionDesc>& p)
|
||||
{
|
||||
const auto& desc = p.second.second;
|
||||
return (("-" + p.first) == key) || (("--" + p.first) == key) || (("-" + desc.shortName) == key) || (
|
||||
("--" + desc.shortName) == key);
|
||||
}
|
||||
);
|
||||
|
||||
if (keyMatch == m_descs.end())
|
||||
{
|
||||
std::cout << "WARNING: Found unknown option: " << key << std::endl;
|
||||
std::cout << "Skipping..." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!keyMatch->second.first) // value option
|
||||
{
|
||||
if (key == arg)
|
||||
{
|
||||
std::cerr << "ERROR: No value set for argument: " << key << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string val = arg.substr(argSplit + 1, arg.size() - argSplit - 1); // take value part of the arg
|
||||
|
||||
try { boost::apply_visitor(OptionVisitor(val), m_values[keyMatch->first]); }
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: Caught exception during option parsing: " << e.what() << std::endl;
|
||||
std::cerr << "Could not parse option with key = " << key << " and value = " << val << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_options.push_back(keyMatch->first);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
void ProgramOptions<TFirst, TTypes...>::printOptionsDesc() const
|
||||
{
|
||||
if (!m_globalDesc.empty()) { std::cout << m_globalDesc << std::endl; }
|
||||
|
||||
std::cout << "TList of available options:\n" << std::endl;
|
||||
|
||||
for (auto& option : m_descs)
|
||||
{
|
||||
std::cout << "Option: --" << option.first << std::endl;
|
||||
const auto& desc = option.second.second;
|
||||
if (!desc.shortName.empty()) { std::cout << "Shortname: --" << desc.shortName << std::endl; }
|
||||
std::cout << "Description: " << std::endl;
|
||||
std::cout << desc.desc << std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
/////// Definition Internal Visitor ///////
|
||||
///////////////////////////////////////////
|
||||
|
||||
template <typename TFirst, typename... TTypes>
|
||||
SProgramOptionsTraits::TokenPair ProgramOptions<TFirst, TTypes...>::OptionVisitor::parsePair(const std::string& str)
|
||||
{
|
||||
const auto split = str.find_first_of(':');
|
||||
const auto size = str.size();
|
||||
|
||||
// (a:b) pattern expected
|
||||
// minimal regex std::regex("\\(.+:.+\\)")
|
||||
if (!(size >= 5 && str[0] == '(' && str[size - 1] == ')') || split == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Failed to parse token pair from value: " + str);
|
||||
}
|
||||
|
||||
// magic 2 numbers is because substr takes a length as second parameter
|
||||
// 2 = remove the last ) + account for the first one
|
||||
return std::make_pair(str.substr(1, split - 1), str.substr(split + 1, size - split - 2));
|
||||
}
|
||||
} // namespace OpenViBE
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ovspTProgramOptions.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
/**
|
||||
* \defgroup ScenarioPlayer Scenario Player
|
||||
*/
|
||||
|
||||
/**
|
||||
* \class EPlayerReturnCodes
|
||||
* \author cgarraud
|
||||
* \date 2016-01-25
|
||||
* \brief Scenario player list of potential return code
|
||||
* \ingroup ScenarioPlayer
|
||||
*/
|
||||
enum class EPlayerReturnCodes
|
||||
{
|
||||
Success = 0, ///< No error during execution */
|
||||
InvalidArg, ///< Invalid command-line options */
|
||||
MissingMandatoryArgument, ///< A mandatory argument is missing */
|
||||
BadArg, ///< An argument is given with a wrong value */
|
||||
OpeningFileFailure, ///< A file could not be opened */
|
||||
ParsingCommandFailure, ///< General parsing command error*/
|
||||
UnkownFailure, ///< Error of unknown type*/
|
||||
KernelLoadingFailure, ///< Kernel loading failed*/
|
||||
KernelInvalidDesc, ///< Invalid kernel descriptor*/
|
||||
KernelInvalidContext, ///< Invalid kernel context*/
|
||||
KernelInternalFailure, ///< Generic error type for kernel internal error*/
|
||||
ScenarioNotLoaded ///< Error triggered when an action is requested on an unknown scenario */
|
||||
};
|
||||
|
||||
/**
|
||||
* \class EPlayerPlayMode
|
||||
* \author cgarraud
|
||||
* \date 2016-01-25
|
||||
* \brief Way of playing a scenario
|
||||
* \ingroup ScenarioPlayer
|
||||
*/
|
||||
enum class EPlayerPlayMode { Standard = 0, Fastfoward };
|
||||
|
||||
/* Define the common parser to be used in the application */
|
||||
using ProgramOptionParser = ProgramOptions<SProgramOptionsTraits::String, SProgramOptionsTraits::Float, SProgramOptionsTraits::TokenPairList>;
|
||||
|
||||
inline std::string toString(const EPlayerReturnCodes code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EPlayerReturnCodes::Success: return "Success";
|
||||
case EPlayerReturnCodes::InvalidArg: return "Invalid Arg";
|
||||
case EPlayerReturnCodes::MissingMandatoryArgument: return "Missing Mandatory Argument";
|
||||
case EPlayerReturnCodes::BadArg: return "Bad Arg";
|
||||
case EPlayerReturnCodes::OpeningFileFailure: return "Opening File Failure";
|
||||
case EPlayerReturnCodes::ParsingCommandFailure: return "Parsing Command Failure";
|
||||
case EPlayerReturnCodes::UnkownFailure: return "Unkown Failure";
|
||||
case EPlayerReturnCodes::KernelLoadingFailure: return "Kernel Loading Failure";
|
||||
case EPlayerReturnCodes::KernelInvalidDesc: return "Kernel Invalid Desc";
|
||||
case EPlayerReturnCodes::KernelInvalidContext: return "Kernel Invalid Context";
|
||||
case EPlayerReturnCodes::KernelInternalFailure: return "Kernel Internal Failure";
|
||||
case EPlayerReturnCodes::ScenarioNotLoaded: return "Scenario Not Loaded";
|
||||
default: return "Invalid Code";
|
||||
}
|
||||
}
|
||||
} // namespace OpenViBE
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE SDK Test Software
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "ovsp_defines.h"
|
||||
#include "ovspCKernelFacade.h"
|
||||
#include "ovspCCommand.h"
|
||||
#include "ovspCCommandLineOptionParser.h"
|
||||
#include "ovspCCommandFileParser.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
void initializeParser(ProgramOptionParser& parser)
|
||||
{
|
||||
const std::string desc =
|
||||
R"d(Usage: program options
|
||||
|
||||
Program can be run in express mode to directly execute a scenario
|
||||
Program can be run in command mode to execute list of commands from a file
|
||||
|
||||
)d";
|
||||
parser.setGlobalDesc(desc);
|
||||
|
||||
parser.addSimpleOption("help", { "h", "Help" });
|
||||
parser.addSimpleOption("version", { "v", "Program version" });
|
||||
|
||||
parser.addValueOption<SProgramOptionsTraits::String>("mode", { "m", "Execution mode: 'x' for express, 'c' for command [mandatory]" });
|
||||
|
||||
// express mode options
|
||||
parser.addValueOption<SProgramOptionsTraits::String>("config-file", { "", "Path to configuration file (express mode only)" });
|
||||
parser.addValueOption<SProgramOptionsTraits::String>("scenario-file", { "", "Path to scenario file (express mode only) [mandatory]" });
|
||||
parser.addValueOption<SProgramOptionsTraits::String>("updated-scenario-file", {
|
||||
"",
|
||||
"Enable update process instead of playing scenario. Path to the updated scenario file (express mode only)."
|
||||
});
|
||||
parser.addValueOption<SProgramOptionsTraits::String>("play-mode",
|
||||
{ "", "Play mode: std for standard and ff for fast-foward (express mode only) [default=std]" });
|
||||
parser.addValueOption<SProgramOptionsTraits::Float>("max-time", { "", "Scenarios playing execution time limit (express mode only)" });
|
||||
parser.addValueOption<SProgramOptionsTraits::TokenPairList>("dg", { "", "Global user-defined token: -dg=\"(token:value)\" (express mode only)" });
|
||||
parser.addValueOption<SProgramOptionsTraits::TokenPairList>("ds", { "", "Scenario user-defined token: -ds=\"(token:value)\" (express mode only)" });
|
||||
|
||||
// command mode options
|
||||
parser.addValueOption<SProgramOptionsTraits::String>("command-file", { "", "Path to command file (command mode only) [mandatory]" });
|
||||
}
|
||||
|
||||
} // namespace OpenViBE
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
OpenViBE::ProgramOptionParser optionParser;
|
||||
initializeParser(optionParser);
|
||||
|
||||
if (!optionParser.parse(argc, argv))
|
||||
{
|
||||
std::cerr << "ERROR: Failed to parse arguments" << std::endl;
|
||||
return int(OpenViBE::EPlayerReturnCodes::InvalidArg);
|
||||
}
|
||||
if (optionParser.hasOption("help"))
|
||||
{
|
||||
optionParser.printOptionsDesc();
|
||||
return int(OpenViBE::EPlayerReturnCodes::Success);
|
||||
}
|
||||
if (optionParser.hasOption("version"))
|
||||
{
|
||||
// PROJECT_VERSION is added to definition from cmake
|
||||
std::cout << "version: " << PROJECT_VERSION << std::endl;
|
||||
return int(OpenViBE::EPlayerReturnCodes::Success);
|
||||
}
|
||||
if (optionParser.hasOption("mode") || optionParser.hasOption("updated-scenario-file"))
|
||||
{
|
||||
// command parser type is selected from mode
|
||||
std::unique_ptr<OpenViBE::ICommandParser> commandParser{ nullptr };
|
||||
const auto mode = optionParser.getOptionValue<OpenViBE::SProgramOptionsTraits::String>("mode");
|
||||
|
||||
if (mode == "c")
|
||||
{
|
||||
// check for the mandatory commad file
|
||||
if (optionParser.hasOption("command-file"))
|
||||
{
|
||||
commandParser.reset(new OpenViBE::CommandFileParser(optionParser.getOptionValue<std::string>("command-file")));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: mandatory option 'command-file' not set" << std::endl;
|
||||
return int(OpenViBE::EPlayerReturnCodes::MissingMandatoryArgument);
|
||||
}
|
||||
}
|
||||
else if ((mode == "x") || optionParser.hasOption("updated-scenario-file")) { commandParser.reset(new OpenViBE::CommandLineOptionParser(optionParser)); }
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: unknown mode set" << std::endl;
|
||||
std::cerr << "Mode must be 'x' or 'c'" << std::endl;
|
||||
return int(OpenViBE::EPlayerReturnCodes::InvalidArg);
|
||||
}
|
||||
|
||||
commandParser->initialize();
|
||||
|
||||
try
|
||||
{
|
||||
auto returnCode = commandParser->parse();
|
||||
|
||||
if (returnCode == OpenViBE::EPlayerReturnCodes::Success)
|
||||
{
|
||||
OpenViBE::CKernelFacade kernel;
|
||||
|
||||
for (auto& cmd : commandParser->getCommandList())
|
||||
{
|
||||
returnCode = cmd->execute(kernel);
|
||||
if (returnCode != OpenViBE::EPlayerReturnCodes::Success) { return int(returnCode); }
|
||||
}
|
||||
}
|
||||
else { return int(returnCode); }
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: received unexpected exception: " << e.what() << std::endl;
|
||||
return int(OpenViBE::EPlayerReturnCodes::UnkownFailure);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: mandatory option 'mode' not set" << std::endl;
|
||||
return int(OpenViBE::EPlayerReturnCodes::MissingMandatoryArgument);
|
||||
}
|
||||
|
||||
return int(OpenViBE::EPlayerReturnCodes::Success);
|
||||
}
|
||||
Reference in New Issue
Block a user