|
Packit Service |
7770af |
#include "sass.hpp"
|
|
Packit Service |
7770af |
#include <iostream>
|
|
Packit Service |
7770af |
#include "output.hpp"
|
|
Packit Service |
7770af |
#include "plugins.hpp"
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
#ifdef _WIN32
|
|
Packit Service |
7770af |
#include <windows.h>
|
|
Packit Service |
7770af |
#else
|
|
Packit Service |
7770af |
#include <sys/types.h>
|
|
Packit Service |
7770af |
#include <dirent.h>
|
|
Packit Service |
7770af |
#include <errno.h>
|
|
Packit Service |
7770af |
#include <dlfcn.h>
|
|
Packit Service |
7770af |
#endif
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
namespace Sass {
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
Plugins::Plugins(void) { }
|
|
Packit Service |
7770af |
Plugins::~Plugins(void)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
for (auto function : functions) {
|
|
Packit Service |
7770af |
sass_delete_function(function);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
for (auto importer : importers) {
|
|
Packit Service |
7770af |
sass_delete_importer(importer);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
for (auto header : headers) {
|
|
Packit Service |
7770af |
sass_delete_importer(header);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// check if plugin is compatible with this version
|
|
Packit Service |
7770af |
// plugins may be linked static against libsass
|
|
Packit Service |
7770af |
// we try to be compatible between major versions
|
|
Packit Service |
7770af |
inline bool compatibility(const char* their_version)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// const char* their_version = "3.1.2";
|
|
Packit Service |
7770af |
// first check if anyone has an unknown version
|
|
Packit Service |
7770af |
const char* our_version = libsass_version();
|
|
Packit Service |
7770af |
if (!strcmp(their_version, "[na]")) return false;
|
|
Packit Service |
7770af |
if (!strcmp(our_version, "[na]")) return false;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// find the position of the second dot
|
|
Packit Service |
7770af |
size_t pos = std::string(our_version).find('.', 0);
|
|
Packit Service |
7770af |
if (pos != std::string::npos) pos = std::string(our_version).find('.', pos + 1);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// if we do not have two dots we fallback to compare complete string
|
|
Packit Service |
7770af |
if (pos == std::string::npos) { return strcmp(their_version, our_version) ? 0 : 1; }
|
|
Packit Service |
7770af |
// otherwise only compare up to the second dot (major versions)
|
|
Packit Service |
7770af |
else { return strncmp(their_version, our_version, pos) ? 0 : 1; }
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// load one specific plugin
|
|
Packit Service |
7770af |
bool Plugins::load_plugin (const std::string& path)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
typedef const char* (*__plugin_version__)(void);
|
|
Packit Service |
7770af |
typedef Sass_Function_List (*__plugin_load_fns__)(void);
|
|
Packit Service |
7770af |
typedef Sass_Importer_List (*__plugin_load_imps__)(void);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
if (LOAD_LIB(plugin, path))
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// try to load initial function to query libsass version suppor
|
|
Packit Service |
7770af |
if (LOAD_LIB_FN(__plugin_version__, plugin_version, "libsass_get_version"))
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// get the libsass version of the plugin
|
|
Packit Service |
7770af |
if (!compatibility(plugin_version())) return false;
|
|
Packit Service |
7770af |
// try to get import address for "libsass_load_functions"
|
|
Packit Service |
7770af |
if (LOAD_LIB_FN(__plugin_load_fns__, plugin_load_functions, "libsass_load_functions"))
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Sass_Function_List fns = plugin_load_functions(), _p = fns;
|
|
Packit Service |
7770af |
while (fns && *fns) { functions.push_back(*fns); ++ fns; }
|
|
Packit Service |
7770af |
sass_free_memory(_p); // only delete the container, items not yet
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// try to get import address for "libsass_load_importers"
|
|
Packit Service |
7770af |
if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Sass_Importer_List imps = plugin_load_importers(), _p = imps;
|
|
Packit Service |
7770af |
while (imps && *imps) { importers.push_back(*imps); ++ imps; }
|
|
Packit Service |
7770af |
sass_free_memory(_p); // only delete the container, items not yet
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// try to get import address for "libsass_load_headers"
|
|
Packit Service |
7770af |
if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_headers, "libsass_load_headers"))
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
Sass_Importer_List imps = plugin_load_headers(), _p = imps;
|
|
Packit Service |
7770af |
while (imps && *imps) { headers.push_back(*imps); ++ imps; }
|
|
Packit Service |
7770af |
sass_free_memory(_p); // only delete the container, items not yet
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// success
|
|
Packit Service |
7770af |
return true;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// print debug message to stderr (should not happen)
|
|
Packit Service |
7770af |
std::cerr << "failed loading 'libsass_support' in <" << path << ">" << std::endl;
|
|
Packit Service |
7770af |
if (const char* dlsym_error = dlerror()) std::cerr << dlsym_error << std::endl;
|
|
Packit Service |
7770af |
CLOSE_LIB(plugin);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
else
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// print debug message to stderr (should not happen)
|
|
Packit Service |
7770af |
std::cerr << "failed loading plugin <" << path << ">" << std::endl;
|
|
Packit Service |
7770af |
if (const char* dlopen_error = dlerror()) std::cerr << dlopen_error << std::endl;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
return false;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
size_t Plugins::load_plugins(const std::string& path)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// count plugins
|
|
Packit Service |
7770af |
size_t loaded = 0;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
#ifdef _WIN32
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
try
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// use wchar (utf16)
|
|
Packit Service |
7770af |
WIN32_FIND_DATAW data;
|
|
Packit Service |
7770af |
// trailing slash is guaranteed
|
|
Packit Service |
7770af |
std::string globsrch(path + "*.dll");
|
|
Packit Service |
7770af |
// convert to wide chars (utf16) for system call
|
|
Packit Service |
7770af |
std::wstring wglobsrch(UTF_8::convert_to_utf16(globsrch));
|
|
Packit Service |
7770af |
HANDLE hFile = FindFirstFileW(wglobsrch.c_str(), &data);
|
|
Packit Service |
7770af |
// check if system called returned a result
|
|
Packit Service |
7770af |
// ToDo: maybe we should print a debug message
|
|
Packit Service |
7770af |
if (hFile == INVALID_HANDLE_VALUE) return -1;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// read directory
|
|
Packit Service |
7770af |
while (true)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
try
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// the system will report the filenames with wide chars (utf16)
|
|
Packit Service |
7770af |
std::string entry = UTF_8::convert_from_utf16(data.cFileName);
|
|
Packit Service |
7770af |
// check if file ending matches exactly
|
|
Packit Service |
7770af |
if (!ends_with(entry, ".dll")) continue;
|
|
Packit Service |
7770af |
// load the plugin and increase counter
|
|
Packit Service |
7770af |
if (load_plugin(path + entry)) ++ loaded;
|
|
Packit Service |
7770af |
// check if there should be more entries
|
|
Packit Service |
7770af |
if (GetLastError() == ERROR_NO_MORE_FILES) break;
|
|
Packit Service |
7770af |
// load next entry (check for return type)
|
|
Packit Service |
7770af |
if (!FindNextFileW(hFile, &data)) break;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
catch (...)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// report the error to the console (should not happen)
|
|
Packit Service |
7770af |
// seems like we got strange data from the system call?
|
|
Packit Service |
7770af |
std::cerr << "filename in plugin path has invalid utf8?" << std::endl;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
catch (utf8::invalid_utf8)
|
|
Packit Service |
7770af |
{
|
|
Packit Service |
7770af |
// report the error to the console (should not happen)
|
|
Packit Service |
7770af |
// implementors should make sure to provide valid utf8
|
|
Packit Service |
7770af |
std::cerr << "plugin path contains invalid utf8" << std::endl;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
#else
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
DIR *dp;
|
|
Packit Service |
7770af |
struct dirent *dirp;
|
|
Packit Service |
7770af |
if((dp = opendir(path.c_str())) == NULL) return -1;
|
|
Packit Service |
7770af |
while ((dirp = readdir(dp)) != NULL) {
|
|
Packit Service |
7770af |
#if __APPLE__
|
|
Packit Service |
7770af |
if (!ends_with(dirp->d_name, ".dylib")) continue;
|
|
Packit Service |
7770af |
#else
|
|
Packit Service |
7770af |
if (!ends_with(dirp->d_name, ".so")) continue;
|
|
Packit Service |
7770af |
#endif
|
|
Packit Service |
7770af |
if (load_plugin(path + dirp->d_name)) ++ loaded;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
closedir(dp);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
#endif
|
|
Packit Service |
7770af |
return loaded;
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|