17 Plugins::Plugins(void) { }
18 Plugins::~Plugins(void)
20 for (auto function : functions) {
21 sass_delete_function(function);
23 for (auto importer : importers) {
24 sass_delete_importer(importer);
26 for (auto header : headers) {
27 sass_delete_importer(header);
31 // check if plugin is compatible with this version
32 // plugins may be linked static against libsass
33 // we try to be compatible between major versions
34 inline bool compatibility(const char* their_version)
36 // const char* their_version = "3.1.2";
37 // first check if anyone has an unknown version
38 const char* our_version = libsass_version();
39 if (!strcmp(their_version, "[na]")) return false;
40 if (!strcmp(our_version, "[na]")) return false;
42 // find the position of the second dot
43 size_t pos = std::string(our_version).find('.', 0);
44 if (pos != std::string::npos) pos = std::string(our_version).find('.', pos + 1);
46 // if we do not have two dots we fallback to compare complete string
47 if (pos == std::string::npos) { return strcmp(their_version, our_version) ? 0 : 1; }
48 // otherwise only compare up to the second dot (major versions)
49 else { return strncmp(their_version, our_version, pos) ? 0 : 1; }
53 // load one specific plugin
54 bool Plugins::load_plugin (const std::string& path)
57 typedef const char* (*__plugin_version__)(void);
58 typedef Sass_Function_List (*__plugin_load_fns__)(void);
59 typedef Sass_Importer_List (*__plugin_load_imps__)(void);
61 if (LOAD_LIB(plugin, path))
63 // try to load initial function to query libsass version suppor
64 if (LOAD_LIB_FN(__plugin_version__, plugin_version, "libsass_get_version"))
66 // get the libsass version of the plugin
67 if (!compatibility(plugin_version())) return false;
68 // try to get import address for "libsass_load_functions"
69 if (LOAD_LIB_FN(__plugin_load_fns__, plugin_load_functions, "libsass_load_functions"))
71 Sass_Function_List fns = plugin_load_functions(), _p = fns;
72 while (fns && *fns) { functions.push_back(*fns); ++ fns; }
73 sass_free_memory(_p); // only delete the container, items not yet
75 // try to get import address for "libsass_load_importers"
76 if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
78 Sass_Importer_List imps = plugin_load_importers(), _p = imps;
79 while (imps && *imps) { importers.push_back(*imps); ++ imps; }
80 sass_free_memory(_p); // only delete the container, items not yet
82 // try to get import address for "libsass_load_headers"
83 if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_headers, "libsass_load_headers"))
85 Sass_Importer_List imps = plugin_load_headers(), _p = imps;
86 while (imps && *imps) { headers.push_back(*imps); ++ imps; }
87 sass_free_memory(_p); // only delete the container, items not yet
94 // print debug message to stderr (should not happen)
95 std::cerr << "failed loading 'libsass_support' in <" << path << ">" << std::endl;
96 if (const char* dlsym_error = dlerror()) std::cerr << dlsym_error << std::endl;
102 // print debug message to stderr (should not happen)
103 std::cerr << "failed loading plugin <" << path << ">" << std::endl;
104 if (const char* dlopen_error = dlerror()) std::cerr << dlopen_error << std::endl;
111 size_t Plugins::load_plugins(const std::string& path)
123 WIN32_FIND_DATAW data;
124 // trailing slash is guaranteed
125 std::string globsrch(path + "*.dll");
126 // convert to wide chars (utf16) for system call
127 std::wstring wglobsrch(UTF_8::convert_to_utf16(globsrch));
128 HANDLE hFile = FindFirstFileW(wglobsrch.c_str(), &data);
129 // check if system called returned a result
130 // ToDo: maybe we should print a debug message
131 if (hFile == INVALID_HANDLE_VALUE) return -1;
138 // the system will report the filenames with wide chars (utf16)
139 std::string entry = UTF_8::convert_from_utf16(data.cFileName);
140 // check if file ending matches exactly
141 if (!ends_with(entry, ".dll")) continue;
142 // load the plugin and increase counter
143 if (load_plugin(path + entry)) ++ loaded;
144 // check if there should be more entries
145 if (GetLastError() == ERROR_NO_MORE_FILES) break;
146 // load next entry (check for return type)
147 if (!FindNextFileW(hFile, &data)) break;
151 // report the error to the console (should not happen)
152 // seems like we got strange data from the system call?
153 std::cerr << "filename in plugin path has invalid utf8?" << std::endl;
157 catch (utf8::invalid_utf8)
159 // report the error to the console (should not happen)
160 // implementors should make sure to provide valid utf8
161 std::cerr << "plugin path contains invalid utf8" << std::endl;
168 if((dp = opendir(path.c_str())) == NULL) return -1;
169 while ((dirp = readdir(dp)) != NULL) {
171 if (!ends_with(dirp->d_name, ".dylib")) continue;
173 if (!ends_with(dirp->d_name, ".so")) continue;
175 if (load_plugin(path + dirp->d_name)) ++ loaded;