summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins/Pluma
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-15 19:10:50 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-15 19:10:50 (GMT)
commitf1700edcd08d6215888e226618555ba43b5324ec (patch)
tree738f30de64f699c3f56d2e15963537c9493a24b4 /src/uscxml/plugins/Pluma
parent2855a9ff7b423140237c9e988252fde0cbacd0a1 (diff)
downloaduscxml-f1700edcd08d6215888e226618555ba43b5324ec.zip
uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.gz
uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.bz2
Refactoring and plugin support
Diffstat (limited to 'src/uscxml/plugins/Pluma')
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Config.hpp141
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Connector.hpp86
-rwxr-xr-xsrc/uscxml/plugins/Pluma/DLibrary.cpp106
-rwxr-xr-xsrc/uscxml/plugins/Pluma/DLibrary.hpp123
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Dir.cpp103
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Dir.hpp64
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Host.cpp179
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Host.hpp212
-rwxr-xr-xsrc/uscxml/plugins/Pluma/PluginManager.cpp201
-rwxr-xr-xsrc/uscxml/plugins/Pluma/PluginManager.hpp245
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Pluma.hpp171
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Pluma.inl52
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Provider.cpp52
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Provider.hpp204
-rwxr-xr-xsrc/uscxml/plugins/Pluma/uce-dirent.h679
15 files changed, 2618 insertions, 0 deletions
diff --git a/src/uscxml/plugins/Pluma/Config.hpp b/src/uscxml/plugins/Pluma/Config.hpp
new file mode 100755
index 0000000..efd98c9
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Config.hpp
@@ -0,0 +1,141 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+//
+// Based on SFML configuration header
+// SFML Config.hpp:
+// http://www.sfml-dev.org/documentation/2.0/Config_8hpp-source.htm
+//
+// Acknowledgements to Simple and Fast Multimedia Library
+// http://www.sfml-dev.org/
+//
+////////////////////////////////////////////////////////////
+
+
+#ifndef PLUMA_CONFIG_HPP
+#define PLUMA_CONFIG_HPP
+
+
+////////////////////////////////////////////////////////////
+// Identify the operating system
+////////////////////////////////////////////////////////////
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+
+ // Windows
+ #define PLUMA_SYS_WINDOWS
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+
+#elif defined(linux) || defined(__linux)
+
+ // Linux
+ #define PLUMA_SYS_LINUX
+
+#elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh)
+
+ // MacOS
+ #define PLUMA_SYS_MACOS
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+
+ // FreeBSD
+ #define PLUMA_SYS_FREEBSD
+
+#else
+
+ // Unsupported system
+ #error This operating system is not supported by this library
+
+#endif
+
+
+
+////////////////////////////////////////////////////////////
+// Define library file extension based on OS
+////////////////////////////////////////////////////////////
+#ifdef PLUMA_SYS_WINDOWS
+ #define PLUMA_LIB_EXTENSION "dll"
+#elif defined(PLUMA_SYS_MACOS)
+ #define PLUMA_LIB_EXTENSION "dylib"
+#elif defined(PLUMA_SYS_LINUX) || defined(PLUMA_SYS_FREEBSD)
+ #define PLUMA_LIB_EXTENSION "so"
+#else
+ // unknown library file type
+ #error Unknown library file extension for this operating system
+#endif
+
+
+////////////////////////////////////////////////////////////
+// Define portable import / export macros
+////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC
+
+ // Windows platforms
+ #ifdef PLUMA_EXPORTS
+
+ // From DLL side, we must export
+ #define PLUMA_API __declspec(dllexport)
+
+ #else
+
+ // From client application side, we must import
+ #define PLUMA_API __declspec(dllimport)
+
+ #endif
+
+ // For Visual C++ compilers, we also need to turn off this annoying C4251 warning.
+ // You can read lots ot different things about it, but the point is the code will
+ // just work fine, and so the simplest way to get rid of this warning is to disable it
+ #ifdef _MSC_VER
+
+ #pragma warning(disable : 4251)
+
+ #endif
+
+ #else
+
+ // No specific directive needed for static build
+ #define PLUMA_API
+
+ #endif
+
+#else
+
+ // Other platforms don't need to define anything
+ #define PLUMA_API
+
+#endif
+
+
+
+
+#endif // PLUMA_CONFIG_HPP
diff --git a/src/uscxml/plugins/Pluma/Connector.hpp b/src/uscxml/plugins/Pluma/Connector.hpp
new file mode 100755
index 0000000..3c227e7
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Connector.hpp
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_CONNECTOR_HPP
+#define PLUMA_CONNECTOR_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Pluma.hpp>
+
+
+/////////////////////////////////////////////////////////////////
+// Define portable import/export macros for Plugin registration
+/////////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC_PLUGIN
+
+ // Windows platforms
+ #ifndef PLUGIN_IMPORTS
+
+ // From DLL side, we must export
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllexport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllexport)
+ #endif
+
+ #else
+
+ // From client application side, we must import
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllimport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllimport)
+ #endif
+
+ #endif
+
+ #else
+
+ // Only define the extern "C" for static build
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+ #endif
+
+#else
+
+ // Only define the extern "C" for other platforms
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+#endif
+
+
+#endif // PLUMA_CONNECTOR_HPP
diff --git a/src/uscxml/plugins/Pluma/DLibrary.cpp b/src/uscxml/plugins/Pluma/DLibrary.cpp
new file mode 100755
index 0000000..9b617db
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/DLibrary.cpp
@@ -0,0 +1,106 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/DLibrary.hpp>
+#include <cstdio>
+#include <string>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+DLibrary* DLibrary::load(const std::string& path){
+ if ( path.empty() ){
+ fprintf(stderr, "Failed to load library: Empty path\n");
+ return NULL;
+ }
+ void* handle = NULL;
+
+ // load library - OS dependent operation
+ #ifdef PLUMA_SYS_WINDOWS
+ handle = ::LoadLibraryA(path.c_str());
+ if (!handle){
+ fprintf(stderr, "Failed to load library \"%s\".\n", path.c_str());
+ return NULL;
+ }
+ #else
+ handle = ::dlopen(path.c_str(), RTLD_NOW);
+ if (!handle){
+ const char* errorString = ::dlerror();
+ fprintf(stderr, "Failed to load library \"%s\".", path.c_str());
+ if(errorString) fprintf(stderr, " OS returned error: \"%s\".", errorString);
+ fprintf(stderr, "\n");
+ return NULL;
+ }
+ #endif
+ // return a DLibrary with the DLL handle
+ return new DLibrary(handle);
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::~DLibrary(){
+ if (handle){
+ #ifdef PLUMA_SYS_WINDOWS
+ ::FreeLibrary( (HMODULE)handle );
+ #else
+ ::dlclose(handle);
+ #endif
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void* DLibrary::getSymbol(const std::string& symbol){
+ if (!handle){
+ fprintf(stderr, "Cannot inspect library symbols, library isn't loaded.\n");
+ return NULL;
+ }
+ void* res;
+ #ifdef PLUMA_SYS_WINDOWS
+ res = (void*)(::GetProcAddress((HMODULE)handle, symbol.c_str()));
+ #else
+ res = (void*)(::dlsym(handle, symbol.c_str()));
+ #endif
+ if (!res){
+ fprintf(stderr, "Library symbol \"%s\" not found.\n", symbol.c_str());
+ return NULL;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::DLibrary(void* handle):
+ handle(handle)
+{
+ // Nothing to do
+}
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/DLibrary.hpp b/src/uscxml/plugins/Pluma/DLibrary.hpp
new file mode 100755
index 0000000..1bb9bac
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/DLibrary.hpp
@@ -0,0 +1,123 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_DYNAMIC_LIBRARY_HPP
+#define PLUMA_DYNAMIC_LIBRARY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+// include OS dependent support for DLL
+#ifdef PLUMA_SYS_WINDOWS
+ #include <Windows.h>
+#else
+ #include <dlfcn.h>
+#endif
+
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages a Dynamic Linking Library.
+///
+////////////////////////////////////////////////////////////
+class DLibrary{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a library.
+ ///
+ /// \param path Path to the library.
+ ///
+ /// \return Pointer to the loaded library, or NULL if failed.
+ ///
+ ////////////////////////////////////////////////////////////
+ static DLibrary* load(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Close and free the opened library (if any).
+ ///
+ ////////////////////////////////////////////////////////////
+ ~DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get a symbol from the library.
+ ///
+ /// \param symbol Symbol that we're looking for.
+ ///
+ /// \return Pointer to what the symbol refers to, or NULL if
+ /// the symbol is not found.
+ ///
+ ////////////////////////////////////////////////////////////
+ void* getSymbol(const std::string& symbol);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// Library instances cannot be created, use load instead.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor via library handle.
+ ///
+ /// Used on load function.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary(void* handle);
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+
+private:
+
+ void* handle; ///< Library handle.
+
+};
+
+
+} // namespace pluma
+
+
+#endif // PLUMA_DYNAMIC_LIBRARY_HPP
diff --git a/src/uscxml/plugins/Pluma/Dir.cpp b/src/uscxml/plugins/Pluma/Dir.cpp
new file mode 100755
index 0000000..860220e
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Dir.cpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Dir.hpp>
+#include <Pluma/uce-dirent.h>
+#include <cstdio>
+#include <queue>
+
+
+namespace pluma{
+
+namespace dir{
+
+
+////////////////////////////////////////////////////////////
+void listFiles(std::list<std::string>& list, const std::string& folder, const std::string& extension, bool recursive){
+ DIR* dir;
+ DIR* subDir;
+ struct dirent *ent;
+ // try to open top folder
+ dir = opendir(folder.c_str());
+ if (dir == NULL){
+ // could not open directory
+ fprintf(stderr, "Could not open \"%s\" directory.\n", folder.c_str());
+ return;
+ }else{
+ // close, we'll process it next
+ closedir(dir);
+ }
+ // enqueue top folder
+ std::queue<std::string> folders;
+ folders.push(folder);
+
+ // run while has queued folders
+ while (!folders.empty()){
+ std::string currFolder = folders.front();
+ folders.pop();
+ dir = opendir(currFolder.c_str());
+ if (dir == NULL) continue;
+ // iterate through all the files and directories
+ while ((ent = readdir (dir)) != NULL) {
+ std::string name(ent->d_name);
+ // ignore "." and ".." directories
+ if ( name.compare(".") == 0 || name.compare("..") == 0) continue;
+ // add path to the file name
+ std::string path = currFolder;
+ path.append("/");
+ path.append(name);
+ // check if it's a folder by trying to open it
+ subDir = opendir(path.c_str());
+ if (subDir != NULL){
+ // it's a folder: close, we can process it later
+ closedir(subDir);
+ if (recursive) folders.push(path);
+ }else{
+ // it's a file
+ if (extension.empty()){
+ list.push_back(path);
+ }else{
+ // check file extension
+ size_t lastDot = name.find_last_of('.');
+ std::string ext = name.substr(lastDot+1);
+ if (ext.compare(extension) == 0){
+ // match
+ list.push_back(path);
+ }
+ } // endif (extension test)
+ } // endif (folder test)
+ } // endwhile (nextFile)
+ closedir(dir);
+ } // endwhile (queued folders)
+
+} // end listFiles
+
+
+} // namespace dir
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Dir.hpp b/src/uscxml/plugins/Pluma/Dir.hpp
new file mode 100755
index 0000000..a94c477
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Dir.hpp
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_DIRECTORY_HPP
+#define PLUMA_DIRECTORY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+#include <list>
+
+
+namespace pluma{
+
+namespace dir{
+
+////////////////////////////////////////////////////////////
+/// \brief List files of a directory.
+///
+/// \param list The output files list.
+/// \param folder The folder where to search in
+/// \param extension A file extension filter,
+/// empty extension will match all files.
+/// \param recursive If true it will list files in
+/// sub directories as well.
+///
+////////////////////////////////////////////////////////////
+void listFiles(
+ std::list<std::string>& list,
+ const std::string& folder,
+ const std::string& extension = "",
+ bool recursive = false
+);
+
+
+} // namespace dir
+
+} // namespace pluma
+
+
+#endif // PLUMA_DIRECTORY_HPP
diff --git a/src/uscxml/plugins/Pluma/Host.cpp b/src/uscxml/plugins/Pluma/Host.cpp
new file mode 100755
index 0000000..eb37c33
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Host.cpp
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Host.hpp>
+#include <cstdio>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Host::Host(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::add(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add a null provider.\n");
+ return false;
+ }
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ addRequests[ provider->plumaGetType() ].push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Host::~Host(){
+ clearProviders();
+ // map frees itself
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::clearProviders(){
+ ProvidersMap::iterator it;
+ for (it = knownTypes.begin() ; it != knownTypes.end() ; ++it){
+ std::list<Provider*>& providers = it->second.providers;
+ std::list<Provider*>::iterator provIt;
+ for (provIt = providers.begin() ; provIt != providers.end() ; ++provIt){
+ delete *provIt;
+ }
+ std::list<Provider*>().swap(providers);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::knows(const std::string& type) const{
+ return knownTypes.find(type) != knownTypes.end();
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.version;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getLowestVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.lowestVersion;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ if (!knows(type)){
+ ProviderInfo pi;
+ pi.version = version;
+ pi.lowestVersion = lowestVersion;
+ knownTypes[type] = pi;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* Host::getProviders(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return &it->second.providers;
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::validateProvider(Provider* provider) const{
+ const std::string& type = provider->plumaGetType();
+ if ( !knows(type) ){
+ fprintf(stderr, "%s provider type isn't registered.\n", type.c_str());
+ return false;
+ }
+ if (!provider->isCompatible(*this)){
+ fprintf(stderr, "Incompatible %s provider version.\n", type.c_str());
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::registerProvider(Provider* provider){
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ knownTypes[ provider->plumaGetType() ].providers.push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::cancelAddictions(){
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ delete *providerIt;
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::confirmAddictions(){
+ if (addRequests.empty()) return false;
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ knownTypes[it->first].providers.push_back(*providerIt);
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+ return true;
+}
+
+
+} //namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Host.hpp b/src/uscxml/plugins/Pluma/Host.hpp
new file mode 100755
index 0000000..cf049f5
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Host.hpp
@@ -0,0 +1,212 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_HOST_HPP
+#define PLUMA_HOST_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+
+#include <vector>
+#include <list>
+#include <map>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages providers.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Host{
+friend class PluginManager;
+friend class Provider;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Add provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool add(Provider* provider);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// New Host instances are not publicly allowed.
+ ///
+ ////////////////////////////////////////////////////////////
+ Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Clears all hosted providers
+ ///
+ ////////////////////////////////////////////////////////////
+ ~Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Ckeck if a provider type is registered.
+ ///
+ /// \param type Provider type id.
+ ///
+ /// \return True if the type is registered
+ ///
+ ////////////////////////////////////////////////////////////
+ bool knows(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get lowest compatible version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The lowest compatible version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getLowestVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a type of providers.
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clears all hosted providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ void clearProviders();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Validate provider type and version.
+ ///
+ /// \return True if the provider is acceptable.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool validateProvider(Provider* provider) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clearly add a provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ /// If acepted, provider is directly stored.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool registerProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are canceled.
+ ///
+ /// Added providers are not stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ void cancelAddictions();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are confirmed.
+ ///
+ /// Added providers are finally stored.
+ ///
+ /// \return True if something was stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ bool confirmAddictions();
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Structure with information about a provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ struct ProviderInfo{
+ unsigned int version;
+ unsigned int lowestVersion;
+ std::list<Provider*> providers;
+ };
+
+ typedef std::map<std::string, ProviderInfo > ProvidersMap;
+ typedef std::map<std::string, std::list<Provider*> > TempProvidersMap;
+
+ ProvidersMap knownTypes; ///< Map of registered types.
+ TempProvidersMap addRequests; ///< Temporarily added providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_HOST_HPP
diff --git a/src/uscxml/plugins/Pluma/PluginManager.cpp b/src/uscxml/plugins/Pluma/PluginManager.cpp
new file mode 100755
index 0000000..1124505
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/PluginManager.cpp
@@ -0,0 +1,201 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/PluginManager.hpp>
+#include <Pluma/DLibrary.hpp>
+#include <Pluma/Dir.hpp>
+#include <cstdio>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+PluginManager::PluginManager(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+PluginManager::~PluginManager(){
+ unloadAll();
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& path){
+ std::string plugName = getPluginName(path);
+ std::string realPath = resolvePathExtension(path);
+ DLibrary* lib = DLibrary::load(realPath);
+ if (!lib) return false;
+
+ fnRegisterPlugin* registerFunction;
+ registerFunction = reinterpret_cast<fnRegisterPlugin*>(lib->getSymbol("connect"));
+
+ if(!registerFunction){
+ fprintf(stderr, "Failed to initialize plugin \"%s\": connect function not found\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ // try to initialize plugin:
+ if (!registerFunction(host)){
+ // plugin decided to fail
+ fprintf(stderr, "Self registry failed on plugin \"%s\".\n", plugName.c_str());
+ host.cancelAddictions();
+ delete lib;
+ return false;
+ }
+ // Store the library if addictions are confirmed
+ if (host.confirmAddictions())
+ libraries[plugName] = lib;
+ else{
+ // otherwise nothing was registered
+ fprintf(stderr, "Nothing registered by plugin \"%s\".\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& folder, const std::string& pluginName){
+ if (folder.empty())
+ return load(pluginName);
+ else if (folder[folder.size()-1] == '/' || folder[folder.size()-1] == '\\')
+ return load(folder + pluginName);
+ return load(folder + '/' + pluginName);
+}
+
+
+////////////////////////////////////////////////////////////
+int PluginManager::loadFromFolder(const std::string& folder, bool recursive){
+ std::list<std::string> files;
+ dir::listFiles(files, folder, PLUMA_LIB_EXTENSION, recursive);
+ // try to load every library
+ int res = 0;
+ std::list<std::string>::const_iterator it;
+ for (it = files.begin() ; it != files.end() ; ++it){
+ if ( load(*it) ) ++res;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::unload(const std::string& pluginName){
+ std::string plugName = getPluginName(pluginName);
+ LibMap::iterator it = libraries.find(plugName);
+ if( it != libraries.end() ) {
+ delete it->second;
+ libraries.erase(it);
+ return true;
+ }
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::unloadAll(){
+
+ host.clearProviders();
+ LibMap::iterator it;
+ for (it = libraries.begin() ; it != libraries.end() ; ++it){
+ delete it->second;
+ }
+ libraries.clear();
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::getPluginName(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension
+ lastDot = path.length();
+ }
+ return path.substr(lastDash, lastDot-lastDash);
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::resolvePathExtension(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension, add it
+ return path + "." + PLUMA_LIB_EXTENSION;
+ }
+ return path;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ host.registerType(type, version, lowestVersion);
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::addProvider(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add null provider\n");
+ return false;
+ }
+ return host.registerProvider(provider);
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::getLoadedPlugins(std::vector<const std::string*>& pluginNames) const{
+ pluginNames.reserve(pluginNames.size()+libraries.size());
+ LibMap::const_iterator it;
+ for(it = libraries.begin() ; it != libraries.end() ; ++it){
+ pluginNames.push_back(&(it->first));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::isLoaded(const std::string& pluginName) const{
+ return libraries.find(getPluginName(pluginName)) != libraries.end();
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* PluginManager::getProviders(const std::string& type) const{
+ return host.getProviders(type);
+}
+
+
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/PluginManager.hpp b/src/uscxml/plugins/Pluma/PluginManager.hpp
new file mode 100755
index 0000000..e5ddf06
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/PluginManager.hpp
@@ -0,0 +1,245 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PLUGIN_MANAGER_HPP
+#define PLUMA_PLUGIN_MANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Host.hpp>
+
+#include <string>
+#include <map>
+
+namespace pluma{
+class DLibrary;
+
+////////////////////////////////////////////////////////////
+/// \brief Manages loaded plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API PluginManager{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ ~PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin given it's path
+ ///
+ /// \param path Path for the plugin, including plugin name. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension isn't present on the path, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& path);
+
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin from a given folder
+ ///
+ /// \param folder The folder path.
+ /// \param pluginName Name of the plugin. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension is omitted, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& folder, const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load all plugins from a given folder
+ ///
+ /// \param folder Path for the folder where the plug-ins are.
+ /// \param recursive If true it will search on sub-folders as well
+ ///
+ /// \return Number of successfully loaded plug-ins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ int loadFromFolder(const std::string& folder, bool recursive = false);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload a plugin.
+ ///
+ /// \param pluginName Name or path of the plugin.
+ ///
+ /// \return True if the plugin is successfully unloaded,
+ /// false if no such plugin exists on the manager.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool unload(const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload all loaded plugins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ void unloadAll();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Directly add a new provider.
+ ///
+ /// \param provider Provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool addProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the name of all loaded plugins.
+ ///
+ /// \param pluginNames A vector to fill with the plugins names.
+ ///
+ ////////////////////////////////////////////////////////////
+ void getLoadedPlugins(std::vector<const std::string*>& pluginNames) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a plug-in is loaded.
+ ///
+ /// \param pluginName the plug-in tname o check.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isLoaded(const std::string& pluginName) const;
+
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// PluginManager cannot be publicly instantiated.
+ ///
+ ////////////////////////////////////////////////////////////
+ PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a provider type
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ /// \see Host::registerType
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ /// \see Host::getProviders
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the plugin name (without extension) from its path
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Name of the plugin.
+ ///
+ /// \see resolvePathExtension
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string getPluginName(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief If the plugin path omits it's extension, this method returns
+ /// the path plus the OS specific dll extension.
+ /// Return a copy of the path otherwise.
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Path with extension.
+ ///
+ /// \see getPluginName
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string resolvePathExtension(const std::string& path);
+
+
+private:
+
+ /// Signature for the plugin's registration function
+ typedef bool fnRegisterPlugin(Host&);
+ typedef std::map<std::string,DLibrary*> LibMap;
+
+ LibMap libraries; ///< Map containing the loaded libraries
+ Host host; ///< Host app proxy, holding all providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_PLUGIN_MANAGER_HPP
diff --git a/src/uscxml/plugins/Pluma/Pluma.hpp b/src/uscxml/plugins/Pluma/Pluma.hpp
new file mode 100755
index 0000000..a9d614e
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Pluma.hpp
@@ -0,0 +1,171 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PLUMA_HPP
+#define PLUMA_PLUMA_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+#include <Pluma/PluginManager.hpp>
+
+////////////////////////////////////////////////////////////
+// Andy macro to convert parameter to string
+////////////////////////////////////////////////////////////
+#define PLUMA_2STRING(X) #X
+
+////////////////////////////////////////////////////////////
+// Macro that helps host applications defining
+// their provider classes
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER(TYPE)\
+PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+virtual TYPE* create() const = 0;\
+PLUMA_PROVIDER_HEADER_END
+
+////////////////////////////////////////////////////////////
+// Macro that generate first part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+class TYPE##Provider: public pluma::Provider{\
+private:\
+ friend class pluma::Pluma;\
+ static const unsigned int PLUMA_INTERFACE_VERSION;\
+ static const unsigned int PLUMA_INTERFACE_LOWEST_VERSION;\
+ static const std::string PLUMA_PROVIDER_TYPE;\
+ std::string plumaGetType() const{ return PLUMA_PROVIDER_TYPE; }\
+public:\
+ unsigned int getVersion() const{ return PLUMA_INTERFACE_VERSION; }
+
+////////////////////////////////////////////////////////////
+// Macro that generate last part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_END };
+
+////////////////////////////////////////////////////////////
+// Macro that generate the provider declaration
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_SOURCE(TYPE, Version, LowestVersion)\
+const std::string TYPE##Provider::PLUMA_PROVIDER_TYPE = PLUMA_2STRING( TYPE );\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_VERSION = Version;\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_LOWEST_VERSION = LowestVersion;
+
+
+////////////////////////////////////////////////////////////
+// Macro that helps plugins generating their provider implementations
+// PRE: SPECIALIZED_TYPE must inherit from BASE_TYPE
+////////////////////////////////////////////////////////////
+#define PLUMA_INHERIT_PROVIDER(SPECIALIZED_TYPE, BASE_TYPE)\
+class SPECIALIZED_TYPE##Provider: public BASE_TYPE##Provider{\
+public:\
+ BASE_TYPE * create() const{ return new SPECIALIZED_TYPE (); }\
+};
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Pluma plugins management
+///
+////////////////////////////////////////////////////////////
+class Pluma: public PluginManager{
+
+public:
+ ////////////////////////////////////////////////////////////
+ /// \brief Default Constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ Pluma();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Tell Pluma to accept a certain type of providers
+ ///
+ /// A Pluma object is able to accept multiple types of providers.
+ /// When a plugin is loaded, it tries to register it's providers
+ /// implementations. Those are only accepted by the host
+ /// application if it's accepting providers of that kind.
+ ///
+ /// \tparam ProviderType type of provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void acceptProviderType();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the stored providers of a certain type.
+ ///
+ /// Providers are added at the end of the \a providers vector.
+ ///
+ /// \tparam ProviderType type of provider to be returned.
+ /// \param[out] providers Vector to fill with the existing
+ /// providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void getProviders(std::vector<ProviderType*>& providers);
+};
+
+#include <Pluma/Pluma.inl>
+
+}
+
+
+#endif // PLUMA_PLUMA_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Pluma
+///
+/// Pluma is the main class of Pluma library. Allows hosting
+/// applications to load/unload dlls in runtime (plugins), and
+/// to get providers of shared interface objects.
+///
+/// Example:
+/// \code
+/// pluma::Pluma pluma;
+/// // Tell it to accept providers of the type DeviceProvider
+/// pluma.acceptProviderType<DeviceProvider>();
+/// // Load some dll
+/// pluma.load("plugins/standard_devices");
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// pluma.getProviders(providers);
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // (...)
+/// delete myDevice;
+/// }
+/// \endcode
+///
+/// It is also possible to add local providers, providers that
+/// are defined directly on the host application. That can
+/// be useful to provide and use default implementations of certain
+/// interfaces, along with plugin implementations.
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/Pluma.inl b/src/uscxml/plugins/Pluma/Pluma.inl
new file mode 100755
index 0000000..c3b6ce7
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Pluma.inl
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+inline Pluma::Pluma(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::acceptProviderType(){
+ PluginManager::registerType(
+ ProviderType::PLUMA_PROVIDER_TYPE,
+ ProviderType::PLUMA_INTERFACE_VERSION,
+ ProviderType::PLUMA_INTERFACE_LOWEST_VERSION
+ );
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::getProviders(std::vector<ProviderType*>& providers){
+ const std::list<Provider*>* lst = PluginManager::getProviders(ProviderType::PLUMA_PROVIDER_TYPE);
+ if (!lst) return;
+ providers.reserve(providers.size() + lst->size());
+ std::list<Provider*>::const_iterator it;
+ for (it = lst->begin() ; it != lst->end() ; ++it)
+ providers.push_back(static_cast<ProviderType*>(*it));
+}
diff --git a/src/uscxml/plugins/Pluma/Provider.cpp b/src/uscxml/plugins/Pluma/Provider.cpp
new file mode 100755
index 0000000..36d4da3
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Provider.cpp
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Provider.hpp>
+#include <Pluma/Host.hpp>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Provider::~Provider(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Provider::isCompatible(const Host& host) const{
+ // check compatibility with host
+ const std::string& type = this->plumaGetType();
+ if (!host.knows(type)) return false;
+ unsigned int lowest = host.getLowestVersion(type);
+ unsigned int current = host.getVersion(type);
+ unsigned int myVersion = this->getVersion();
+ return lowest <= myVersion && myVersion <= current;
+}
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Provider.hpp b/src/uscxml/plugins/Pluma/Provider.hpp
new file mode 100755
index 0000000..ea06497
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Provider.hpp
@@ -0,0 +1,204 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PROVIDER_HPP
+#define PLUMA_PROVIDER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+
+namespace pluma{
+class Host;
+
+////////////////////////////////////////////////////////////
+/// \brief Interface to provide applications with objects from plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Provider{
+friend class Host;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual ~Provider();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider version.
+ ///
+ /// \return Version number.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual unsigned int getVersion() const = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check compatibility with host.
+ ///
+ /// The same provider may be compiled with different versions
+ /// on host side and on plugins side. This function checks if
+ /// a plugin provider is compatible with the current version of
+ /// the same provider type on the host side.
+ ///
+ /// \param host Host, proxy of host application.
+ ///
+ /// \return True if it's compatible with \a host.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isCompatible(const Host& host) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider type.
+ ///
+ /// Each provider defined on the host application is identified by
+ /// a unique type. Those types are automatically managed internally by
+ /// pluma.
+ ///
+ /// \return Provider type id.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual std::string plumaGetType() const = 0;
+
+};
+
+} // namespace pluma
+
+
+#endif // PLUMA_PROVIDER_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Provider
+/// The plugin specific implementations are unknown at the host side,
+/// only their shared interfaces are known. Then, host app needs a generic
+/// way of create interface objects. That's what provider classes are for.
+/// It is the factory design pattern
+/// (http://www.oodesign.com/factory-pattern.html)
+///
+/// Shared interfaces define their provider types (by inheriting from
+/// pluma::Provider). Hosts then use those tipes to get objects from the
+/// plugins.
+/// Plugins derive the shared interface providers so that they can provide
+/// host with specific implementations of the shared interface.
+/// Those specific providers are given to the host through a connect function.
+///
+///
+/// Example: A host app uses objects of type Device. A certain plugin
+/// defines a Keyboard, witch is a Device.
+/// The Host will use DeviceProviders to create objects of type Device.
+/// The plugin will provide host specifically with a KeyboardProvider.
+/// Other plugins may provide host with other derived DeviceProvider types.
+///
+/// Device hpp (shared):
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// class Device{
+/// public:
+/// virtual std::string getDescription() const = 0;
+/// };
+/// // create DevicedProvider class
+/// PLUMA_PROVIDER_HEADER(Device);
+/// \endcode
+///
+/// Device cpp (shared):
+/// \code
+/// #include "Device.hpp"
+/// generate DevicedProvider with version 6, and compatible with at least v.3
+/// PLUMA_PROVIDER_SOURCE(Device, 6, 3);
+/// \endcode
+///
+///
+/// <br>
+/// Keyboard code on the plugin side:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// #include "Device.hpp"
+///
+/// class Keyboard: public Device{
+/// public:
+/// std::string getDescription() const{
+/// return "keyboard";
+/// }
+/// };
+///
+/// // create KeyboardProvider, it implements DeviceProvider
+/// PLUMA_INHERIT_PROVIDER(Keyboard, Device);
+/// \endcode
+///
+/// plugin connector:
+/// \code
+/// #include <Pluma/Connector.hpp>
+/// #include "Keyboard.hpp"
+///
+/// PLUMA_CONNECTOR
+/// bool connect(pluma::Host& host){
+/// // add a keyboard provider to host
+/// host.add( new KeyboardProvider() );
+/// return true;
+/// }
+/// \endcode
+///
+///
+/// Host application code:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+///
+/// #include "Device.hpp"
+/// #include <iostream>
+/// #include <vector>
+///
+/// int main(){
+///
+/// pluma::Pluma plugins;
+/// // Tell plugins manager to accept providers of the type DeviceProvider
+/// plugins.acceptProviderType<DeviceProvider>();
+/// // Load library "standard_devices" from folder "plugins"
+/// plugins.load("plugins", "standard_devices");
+///
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// plugins.getProviders(providers);
+///
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // and delete it in the end
+/// delete myDevice;
+/// }
+/// return 0;
+/// }
+/// \endcode
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/uce-dirent.h b/src/uscxml/plugins/Pluma/uce-dirent.h
new file mode 100755
index 0000000..ecf78eb
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/uce-dirent.h
@@ -0,0 +1,679 @@
+/*
+ * uce-dirent.h - operating system independent dirent implementation
+ *
+ * Copyright (C) 1998-2002 Toni Ronkko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * ``Software''), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi>
+ *
+ * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $
+ *
+ * $Log: uce-dirent.h,v $
+ * Revision 1.7 2002/05/13 10:48:35 tr
+ * embedded some source code directly to the header so that no source
+ * modules need to be included in the MS Visual C project using the
+ * interface, removed all the dependencies to other headers of the `uce'
+ * library so that the header can be made public
+ *
+ * Revision 1.6 2002/04/12 16:22:04 tr
+ * Unified Compiling Environment (UCE) replaced `std' library
+ *
+ * Revision 1.5 2001/07/20 16:33:40 tr
+ * moved to `std' library and re-named defines accordingly
+ *
+ * Revision 1.4 2001/07/10 16:47:18 tronkko
+ * revised comments
+ *
+ * Revision 1.3 2001/01/11 13:16:43 tr
+ * using ``uce-machine.h'' for finding out defines such as `FREEBSD'
+ *
+ * Revision 1.2 2000/10/08 16:00:41 tr
+ * copy of FreeBSD man page
+ *
+ * Revision 1.1 2000/07/10 05:53:16 tr
+ * Initial revision
+ *
+ * Revision 1.2 1998/07/19 18:29:14 tr
+ * Added error reporting capabilities and some asserts.
+ *
+ * Revision 1.1 1998/07/04 16:27:51 tr
+ * Initial revision
+ *
+ *
+ * MSVC 1.0 scans automatic dependencies incorrectly when your project
+ * contains this very header. The problem is that MSVC cannot handle
+ * include directives inside #if..#endif block those are never entered.
+ * Since this header ought to compile in many different operating systems,
+ * there had to be several conditional blocks that are compiled only in
+ * operating systems for what they were designed for. MSVC 1.0 cannot
+ * handle inclusion of sys/dir.h in a part that is compiled only in Apollo
+ * operating system. To fix the problem you need to insert DIR.H into
+ * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++.
+ * Consult manuals for more informaton about the problem.
+ *
+ * Since many UNIX systems have dirent.h we assume to have one also.
+ * However, if your UNIX system does not have dirent.h you can download one
+ * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz.
+ * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h,
+ * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H,
+ * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and
+ * HAVE_SYS_NDIR_H according to the files found.
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+#define DIRENT_H_INCLUDED
+
+/* find out platform */
+#if defined(MSDOS) /* MS-DOS */
+#elif defined(__MSDOS__) /* Turbo C/Borland */
+# define MSDOS
+#elif defined(__DOS__) /* Watcom */
+# define MSDOS
+#endif
+
+#if defined(WIN32) /* MS-Windows */
+#elif defined(__NT__) /* Watcom */
+# define WIN32
+#elif defined(_WIN32) /* Microsoft */
+# define WIN32
+#elif defined(__WIN32__) /* Borland */
+# define WIN32
+#endif
+
+/*
+ * See what kind of dirent interface we have unless autoconf has already
+ * determinated that.
+ */
+#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H)
+# if defined(_MSC_VER) /* Microsoft C/C++ */
+ /* no dirent.h */
+# elif defined(__BORLANDC__) /* Borland C/C++ */
+# define HAVE_DIRENT_H
+# define VOID_CLOSEDIR
+# elif defined(__TURBOC__) /* Borland Turbo C */
+ /* no dirent.h */
+# elif defined(__WATCOMC__) /* Watcom C/C++ */
+# define HAVE_DIRECT_H
+# elif defined(__apollo) /* Apollo */
+# define HAVE_SYS_DIR_H
+# elif defined(__hpux) /* HP-UX */
+# define HAVE_DIRENT_H
+# elif defined(__alpha) || defined(__alpha__) /* Alpha OSF1 */
+# error "not implemented"
+# elif defined(__sgi) /* Silicon Graphics */
+# define HAVE_DIRENT_H
+# elif defined(sun) || defined(_sun) /* Sun Solaris */
+# define HAVE_DIRENT_H
+# elif defined(__FreeBSD__) /* FreeBSD */
+# define HAVE_DIRENT_H
+# elif defined(__linux__) /* Linux */
+# define HAVE_DIRENT_H
+# elif defined(__GNUC__) /* GNU C/C++ */
+# define HAVE_DIRENT_H
+# else
+# error "not implemented"
+# endif
+#endif
+
+/* include proper interface headers */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+# ifdef FREEBSD
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+# else
+# define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
+# endif
+
+#elif defined(HAVE_NDIR_H)
+# include <ndir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_SYS_NDIR_H)
+# include <sys/ndir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_DIRECT_H)
+# include <direct.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_DIR_H)
+# include <dir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_SYS_DIR_H)
+# include <sys/types.h>
+# include <sys/dir.h>
+# ifndef dirent
+# define dirent direct
+# endif
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(MSDOS) || defined(WIN32)
+
+ /* figure out type of underlaying directory interface to be used */
+# if defined(WIN32)
+# define DIRENT_WIN32_INTERFACE
+# elif defined(MSDOS)
+# define DIRENT_MSDOS_INTERFACE
+# else
+# error "missing native dirent interface"
+# endif
+
+ /*** WIN32 specifics ***/
+# if defined(DIRENT_WIN32_INTERFACE)
+# include <windows.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN (MAX_PATH)
+# endif
+
+
+ /*** MS-DOS specifics ***/
+# elif defined(DIRENT_MSDOS_INTERFACE)
+# include <dos.h>
+
+ /* Borland defines file length macros in dir.h */
+# if defined(__BORLANDC__)
+# include <dir.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
+# endif
+# if !defined(_find_t)
+# define _find_t find_t
+# endif
+
+ /* Turbo C defines ffblk structure in dir.h */
+# elif defined(__TURBOC__)
+# include <dir.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
+# endif
+# define DIRENT_USE_FFBLK
+
+ /* MSVC */
+# elif defined(_MSC_VER)
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN (12)
+# endif
+
+ /* Watcom */
+# elif defined(__WATCOMC__)
+# if !defined(DIRENT_MAXNAMLEN)
+# if defined(__OS2__) || defined(__NT__)
+# define DIRENT_MAXNAMLEN (255)
+# else
+# define DIRENT_MAXNAMLEN (12)
+# endif
+# endif
+
+# endif
+# endif
+
+ /*** generic MS-DOS and MS-Windows stuff ***/
+# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN)
+# define NAME_MAX DIRENT_MAXNAMLEN
+# endif
+# if NAME_MAX < DIRENT_MAXNAMLEN
+# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN"
+# endif
+
+
+ /*
+ * Substitute for real dirent structure. Note that `d_name' field is a
+ * true character array although we have it copied in the implementation
+ * dependent data. We could save some memory if we had declared `d_name'
+ * as a pointer refering the name within implementation dependent data.
+ * We have not done that since some code may rely on sizeof(d_name) to be
+ * something other than four. Besides, directory entries are typically so
+ * small that it takes virtually no time to copy them from place to place.
+ */
+ typedef struct dirent {
+ char d_name[NAME_MAX + 1];
+
+ /*** Operating system specific part ***/
+# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/
+ WIN32_FIND_DATA data;
+# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/
+# if defined(DIRENT_USE_FFBLK)
+ struct ffblk data;
+# else
+ struct _find_t data;
+# endif
+# endif
+ } dirent;
+
+ /* DIR substitute structure containing directory name. The name is
+ * essential for the operation of ``rewinndir'' function. */
+ typedef struct DIR {
+ char *dirname; /* directory being scanned */
+ dirent current; /* current entry */
+ int dirent_filled; /* is current un-processed? */
+
+ /*** Operating system specific part ***/
+# if defined(DIRENT_WIN32_INTERFACE)
+ HANDLE search_handle;
+# elif defined(DIRENT_MSDOS_INTERFACE)
+# endif
+ } DIR;
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* supply prototypes for dirent functions */
+static DIR *opendir (const char *dirname);
+static struct dirent *readdir (DIR *dirp);
+static int closedir (DIR *dirp);
+static void rewinddir (DIR *dirp);
+
+/*
+ * Implement dirent interface as static functions so that the user does not
+ * need to change his project in any way to use dirent function. With this
+ * it is sufficient to include this very header from source modules using
+ * dirent functions and the functions will be pulled in automatically.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+/* use ffblk instead of _find_t if requested */
+#if defined(DIRENT_USE_FFBLK)
+# define _A_ARCH (FA_ARCH)
+# define _A_HIDDEN (FA_HIDDEN)
+# define _A_NORMAL (0)
+# define _A_RDONLY (FA_RDONLY)
+# define _A_SUBDIR (FA_DIREC)
+# define _A_SYSTEM (FA_SYSTEM)
+# define _A_VOLID (FA_LABEL)
+# define _dos_findnext(dest) findnext(dest)
+# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags)
+#endif
+
+static int _initdir (DIR *p);
+static const char *_getdirname (const struct dirent *dp);
+static void _setdirname (struct DIR *dirp);
+
+/*
+ * <function name="opendir">
+ * <intro>open directory stream for reading
+ * <syntax>DIR *opendir (const char *dirname);
+ *
+ * <desc>Open named directory stream for read and return pointer to the
+ * internal working area that is used for retrieving individual directory
+ * entries. The internal working area has no fields of your interest.
+ *
+ * <ret>Returns a pointer to the internal working area or NULL in case the
+ * directory stream could not be opened. Global `errno' variable will set
+ * in case of error as follows:
+ *
+ * <table>
+ * [EACESS |Permission denied.
+ * [EMFILE |Too many open files used by the process.
+ * [ENFILE |Too many open files in system.
+ * [ENOENT |Directory does not exist.
+ * [ENOMEM |Insufficient memory.
+ * [ENOTDIR |dirname does not refer to directory. This value is not
+ * reliable on MS-DOS and MS-Windows platforms. Many
+ * implementations return ENOENT even when the name refers to a
+ * file.]
+ * </table>
+ * </function>
+ */
+static DIR *
+opendir(
+ const char *dirname)
+{
+ DIR *dirp;
+ assert (dirname != NULL);
+
+ dirp = (DIR*)malloc (sizeof (struct DIR));
+ if (dirp != NULL) {
+ char *p;
+
+ /* allocate room for directory name */
+ dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*"));
+ if (dirp->dirname == NULL) {
+ /* failed to duplicate directory name. errno set by malloc() */
+ free (dirp);
+ return NULL;
+ }
+ /* Copy directory name while appending directory separator and "*.*".
+ * Directory separator is not appended if the name already ends with
+ * drive or directory separator. Directory separator is assumed to be
+ * '/' or '\' and drive separator is assumed to be ':'. */
+ strcpy (dirp->dirname, dirname);
+ p = strchr (dirp->dirname, '\0');
+ if (dirp->dirname < p &&
+ *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':')
+ {
+ strcpy (p++, "/");
+ }
+# ifdef DIRENT_WIN32_INTERFACE
+ strcpy (p, "*"); /*scan files with and without extension in win32*/
+# else
+ strcpy (p, "*.*"); /*scan files with and without extension in DOS*/
+# endif
+
+ /* open stream */
+ if (_initdir (dirp) == 0) {
+ /* initialization failed */
+ free (dirp->dirname);
+ free (dirp);
+ return NULL;
+ }
+ }
+ return dirp;
+}
+
+
+/*
+ * <function name="readdir">
+ * <intro>read a directory entry
+ * <syntax>struct dirent *readdir (DIR *dirp);
+ *
+ * <desc>Read individual directory entry and return pointer to a structure
+ * containing the name of the entry. Individual directory entries returned
+ * include normal files, sub-directories, pseudo-directories "." and ".."
+ * and also volume labels, hidden files and system files in MS-DOS and
+ * MS-Windows. You might want to use stat(2) function to determinate which
+ * one are you dealing with. Many dirent implementations already contain
+ * equivalent information in dirent structure but you cannot depend on
+ * this.
+ *
+ * The dirent structure contains several system dependent fields that
+ * generally have no interest to you. The only interesting one is char
+ * d_name[] that is also portable across different systems. The d_name
+ * field contains the name of the directory entry without leading path.
+ * While d_name is portable across different systems the actual storage
+ * capacity of d_name varies from system to system and there is no portable
+ * way to find out it at compile time as different systems define the
+ * capacity of d_name with different macros and some systems do not define
+ * capacity at all (besides actual declaration of the field). If you really
+ * need to find out storage capacity of d_name then you might want to try
+ * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought
+ * there are many MS-DOS and MS-Windows implementations those do not define
+ * it. There are also systems that declare d_name as "char d_name[1]" and
+ * then allocate suitable amount of memory at run-time. Thanks to Alain
+ * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me.
+ *
+ * This all leads to the fact that it is difficult to allocate space
+ * for the directory names when the very same program is being compiled on
+ * number of operating systems. Therefore I suggest that you always
+ * allocate space for directory names dynamically.
+ *
+ * <ret>
+ * Returns a pointer to a structure containing name of the directory entry
+ * in `d_name' field or NULL if there was an error. In case of an error the
+ * global `errno' variable will set as follows:
+ *
+ * <table>
+ * [EBADF |dir parameter refers to an invalid directory stream. This value
+ * is not set reliably on all implementations.]
+ * </table>
+ * </function>
+ */
+static struct dirent *
+readdir (DIR *dirp)
+{
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+ /* directory stream was opened/rewound incorrectly or it ended normally */
+ errno = EBADF;
+ return NULL;
+ }
+#endif
+
+ if (dirp->dirent_filled != 0) {
+ /*
+ * Directory entry has already been retrieved and there is no need to
+ * retrieve a new one. Directory entry will be retrieved in advance
+ * when the user calls readdir function for the first time. This is so
+ * because real dirent has separate functions for opening and reading
+ * the stream whereas Win32 and DOS dirents open the stream
+ * automatically when we retrieve the first file. Therefore, we have to
+ * save the first file when opening the stream and later we have to
+ * return the saved entry when the user tries to read the first entry.
+ */
+ dirp->dirent_filled = 0;
+ } else {
+ /* fill in entry and return that */
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) {
+ /* Last file has been processed or an error occured */
+ FindClose (dirp->search_handle);
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+ errno = ENOENT;
+ return NULL;
+ }
+
+# elif defined(DIRENT_MSDOS_INTERFACE)
+ if (_dos_findnext (&dirp->current.data) != 0) {
+ /* _dos_findnext and findnext will set errno to ENOENT when no
+ * more entries could be retrieved. */
+ return NULL;
+ }
+# endif
+
+ _setdirname (dirp);
+ assert (dirp->dirent_filled == 0);
+ }
+ return &dirp->current;
+}
+
+
+/*
+ * <function name="closedir">
+ * <intro>close directory stream.
+ * <syntax>int closedir (DIR *dirp);
+ *
+ * <desc>Close directory stream opened by the `opendir' function. Close of
+ * directory stream invalidates the DIR structure as well as previously read
+ * dirent entry.
+ *
+ * <ret>The function typically returns 0 on success and -1 on failure but
+ * the function may be declared to return void on same systems. At least
+ * Borland C/C++ and some UNIX implementations use void as a return type.
+ * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is
+ * known to return nothing. The very same definition is made by the GNU
+ * autoconf if you happen to use it.
+ *
+ * The global `errno' variable will set to EBADF in case of error.
+ * </function>
+ */
+static int
+closedir (DIR *dirp)
+{
+ int retcode = 0;
+
+ /* make sure that dirp points to legal structure */
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* free directory name and search handles */
+ if (dirp->dirname != NULL) free (dirp->dirname);
+
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ if (FindClose (dirp->search_handle) == FALSE) {
+ /* Unknown error */
+ retcode = -1;
+ errno = EBADF;
+ }
+ }
+#endif
+
+ /* clear dirp structure to make sure that it cannot be used anymore*/
+ memset (dirp, 0, sizeof (*dirp));
+# if defined(DIRENT_WIN32_INTERFACE)
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+# endif
+
+ free (dirp);
+ return retcode;
+}
+
+
+/*
+ * <function name="rewinddir">
+ * <intro>rewind directory stream to the beginning
+ * <syntax>void rewinddir (DIR *dirp);
+ *
+ * <desc>Rewind directory stream to the beginning so that the next call of
+ * readdir() returns the very first directory entry again. However, note
+ * that next call of readdir() may not return the same directory entry as it
+ * did in first time. The directory stream may have been affected by newly
+ * created files.
+ *
+ * Almost every dirent implementation ensure that rewinddir will update
+ * the directory stream to reflect any changes made to the directory entries
+ * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on
+ * this if your program depends on the feature. I know at least one dirent
+ * implementation where you are required to close and re-open the stream to
+ * see the changes.
+ *
+ * <ret>Returns nothing. If something went wrong while rewinding, you will
+ * notice it later when you try to retrieve the first directory entry.
+ */
+static void
+rewinddir (DIR *dirp)
+{
+ /* make sure that dirp is legal */
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return;
+ }
+ assert (dirp->dirname != NULL);
+
+ /* close previous stream */
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ if (FindClose (dirp->search_handle) == FALSE) {
+ /* Unknown error */
+ errno = EBADF;
+ }
+ }
+#endif
+
+ /* re-open previous stream */
+ if (_initdir (dirp) == 0) {
+ /* initialization failed but we cannot deal with error. User will notice
+ * error later when she tries to retrieve first directory enty. */
+ /*EMPTY*/;
+ }
+}
+
+
+/*
+ * Open native directory stream object and retrieve first file.
+ * Be sure to close previous stream before opening new one.
+ */
+static int
+_initdir (DIR *dirp)
+{
+ assert (dirp != NULL);
+ assert (dirp->dirname != NULL);
+ dirp->dirent_filled = 0;
+
+# if defined(DIRENT_WIN32_INTERFACE)
+ /* Open stream and retrieve first file */
+ dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data);
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+ /* something went wrong but we don't know what. GetLastError() could
+ * give us more information about the error, but then we should map
+ * the error code into errno. */
+ errno = ENOENT;
+ return 0;
+ }
+
+# elif defined(DIRENT_MSDOS_INTERFACE)
+ if (_dos_findfirst (dirp->dirname,
+ _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN,
+ &dirp->current.data) != 0)
+ {
+ /* _dos_findfirst and findfirst will set errno to ENOENT when no
+ * more entries could be retrieved. */
+ return 0;
+ }
+# endif
+
+ /* initialize DIR and it's first entry */
+ _setdirname (dirp);
+ dirp->dirent_filled = 1;
+ return 1;
+}
+
+
+/*
+ * Return implementation dependent name of the current directory entry.
+ */
+static const char *
+_getdirname (const struct dirent *dp)
+{
+#if defined(DIRENT_WIN32_INTERFACE)
+ return dp->data.cFileName;
+
+#elif defined(DIRENT_USE_FFBLK)
+ return dp->data.ff_name;
+
+#else
+ return dp->data.name;
+#endif
+}
+
+
+/*
+ * Copy name of implementation dependent directory entry to the d_name field.
+ */
+static void
+_setdirname (struct DIR *dirp) {
+ /* make sure that d_name is long enough */
+ assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX);
+
+ strncpy (dirp->current.d_name,
+ _getdirname (&dirp->current),
+ NAME_MAX);
+ dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/
+}
+
+# ifdef __cplusplus
+}
+# endif
+# define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
+
+#else
+# error "missing dirent interface"
+#endif
+
+
+#endif /*DIRENT_H*/
+