Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / plugins.cpp
1 #include "sass.hpp"
2 #include <iostream>
3 #include "output.hpp"
4 #include "plugins.hpp"
5
6 #ifdef _WIN32
7 #include <windows.h>
8 #else
9 #include <sys/types.h>
10 #include <dirent.h>
11 #include <errno.h>
12 #include <dlfcn.h>
13 #endif
14
15 namespace Sass {
16
17   Plugins::Plugins(void) { }
18   Plugins::~Plugins(void)
19   {
20     for (auto function : functions) {
21       sass_delete_function(function);
22     }
23     for (auto importer : importers) {
24       sass_delete_importer(importer);
25     }
26     for (auto header : headers) {
27       sass_delete_importer(header);
28     }
29   }
30
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)
35   {
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;
41
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);
45
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; }
50
51   }
52
53   // load one specific plugin
54   bool Plugins::load_plugin (const std::string& path)
55   {
56
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);
60
61     if (LOAD_LIB(plugin, path))
62     {
63       // try to load initial function to query libsass version suppor
64       if (LOAD_LIB_FN(__plugin_version__, plugin_version, "libsass_get_version"))
65       {
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"))
70         {
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
74         }
75         // try to get import address for "libsass_load_importers"
76         if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
77         {
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
81         }
82         // try to get import address for "libsass_load_headers"
83         if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_headers, "libsass_load_headers"))
84         {
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
88         }
89         // success
90         return true;
91       }
92       else
93       {
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;
97         CLOSE_LIB(plugin);
98       }
99     }
100     else
101     {
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;
105     }
106
107     return false;
108
109   }
110
111   size_t Plugins::load_plugins(const std::string& path)
112   {
113
114     // count plugins
115     size_t loaded = 0;
116
117     #ifdef _WIN32
118
119       try
120       {
121
122         // use wchar (utf16)
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;
132
133         // read directory
134         while (true)
135         {
136           try
137           {
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;
148           }
149           catch (...)
150           {
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;
154           }
155         }
156       }
157       catch (utf8::invalid_utf8)
158       {
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;
162       }
163
164     #else
165
166       DIR *dp;
167       struct dirent *dirp;
168       if((dp  = opendir(path.c_str())) == NULL) return -1;
169       while ((dirp = readdir(dp)) != NULL) {
170         #if __APPLE__
171           if (!ends_with(dirp->d_name, ".dylib")) continue;
172         #else
173           if (!ends_with(dirp->d_name, ".so")) continue;
174         #endif
175         if (load_plugin(path + dirp->d_name)) ++ loaded;
176       }
177       closedir(dp);
178
179     #endif
180     return loaded;
181
182   }
183
184 }