sassc 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/ext/libsass/.gitignore +13 -6
  4. data/ext/libsass/Makefile +42 -26
  5. data/ext/libsass/Makefile.am +43 -30
  6. data/ext/libsass/Readme.md +4 -2
  7. data/ext/libsass/appveyor.yml +10 -14
  8. data/ext/libsass/ast.cpp +54 -44
  9. data/ext/libsass/ast.hpp +404 -236
  10. data/ext/libsass/ast_def_macros.hpp +5 -0
  11. data/ext/libsass/ast_factory.hpp +6 -3
  12. data/ext/libsass/ast_fwd_decl.hpp +12 -0
  13. data/ext/libsass/b64/encode.h +2 -2
  14. data/ext/libsass/backtrace.hpp +13 -17
  15. data/ext/libsass/base64vlq.hpp +4 -1
  16. data/ext/libsass/bind.cpp +12 -15
  17. data/ext/libsass/bind.hpp +6 -6
  18. data/ext/libsass/color_names.hpp +4 -1
  19. data/ext/libsass/configure.ac +7 -21
  20. data/ext/libsass/constants.cpp +6 -4
  21. data/ext/libsass/constants.hpp +10 -4
  22. data/ext/libsass/context.cpp +89 -58
  23. data/ext/libsass/context.hpp +28 -35
  24. data/ext/libsass/contextualize.cpp +20 -10
  25. data/ext/libsass/contextualize.hpp +8 -23
  26. data/ext/libsass/contrib/libsass.spec +66 -0
  27. data/ext/libsass/cssize.cpp +547 -0
  28. data/ext/libsass/cssize.hpp +82 -0
  29. data/ext/libsass/debug.hpp +3 -3
  30. data/ext/libsass/debugger.hpp +358 -0
  31. data/ext/libsass/emitter.cpp +255 -0
  32. data/ext/libsass/emitter.hpp +83 -0
  33. data/ext/libsass/environment.hpp +7 -3
  34. data/ext/libsass/error_handling.cpp +11 -14
  35. data/ext/libsass/error_handling.hpp +9 -7
  36. data/ext/libsass/eval.cpp +253 -161
  37. data/ext/libsass/eval.hpp +13 -13
  38. data/ext/libsass/expand.cpp +135 -64
  39. data/ext/libsass/expand.hpp +11 -13
  40. data/ext/libsass/extend.cpp +66 -20
  41. data/ext/libsass/extend.hpp +6 -11
  42. data/ext/libsass/file.cpp +31 -26
  43. data/ext/libsass/file.hpp +6 -1
  44. data/ext/libsass/functions.cpp +270 -287
  45. data/ext/libsass/functions.hpp +8 -11
  46. data/ext/libsass/inspect.cpp +385 -255
  47. data/ext/libsass/inspect.hpp +15 -26
  48. data/ext/libsass/kwd_arg_macros.hpp +5 -0
  49. data/ext/libsass/mapping.hpp +4 -3
  50. data/ext/libsass/memory_manager.hpp +5 -2
  51. data/ext/libsass/node.cpp +50 -50
  52. data/ext/libsass/node.hpp +26 -27
  53. data/ext/libsass/operation.hpp +15 -4
  54. data/ext/libsass/output.cpp +401 -0
  55. data/ext/libsass/output.hpp +56 -0
  56. data/ext/libsass/parser.cpp +573 -399
  57. data/ext/libsass/parser.hpp +122 -88
  58. data/ext/libsass/paths.hpp +7 -2
  59. data/ext/libsass/plugins.cpp +155 -0
  60. data/ext/libsass/plugins.hpp +56 -0
  61. data/ext/libsass/position.cpp +128 -0
  62. data/ext/libsass/position.hpp +108 -11
  63. data/ext/libsass/prelexer.cpp +184 -110
  64. data/ext/libsass/prelexer.hpp +131 -24
  65. data/ext/libsass/remove_placeholders.cpp +1 -1
  66. data/ext/libsass/remove_placeholders.hpp +6 -6
  67. data/ext/libsass/sass.cpp +3 -3
  68. data/ext/libsass/sass.h +12 -4
  69. data/ext/libsass/sass2scss.cpp +3 -2
  70. data/ext/libsass/sass2scss.h +5 -0
  71. data/ext/libsass/sass_context.cpp +136 -37
  72. data/ext/libsass/sass_context.h +19 -10
  73. data/ext/libsass/sass_functions.cpp +29 -2
  74. data/ext/libsass/sass_functions.h +8 -2
  75. data/ext/libsass/sass_interface.cpp +32 -23
  76. data/ext/libsass/sass_interface.h +9 -4
  77. data/ext/libsass/sass_util.cpp +19 -23
  78. data/ext/libsass/sass_util.hpp +28 -27
  79. data/ext/libsass/sass_values.cpp +6 -4
  80. data/ext/libsass/sass_values.h +3 -3
  81. data/ext/libsass/script/ci-build-libsass +13 -1
  82. data/ext/libsass/script/ci-report-coverage +2 -1
  83. data/ext/libsass/source_map.cpp +79 -28
  84. data/ext/libsass/source_map.hpp +35 -16
  85. data/ext/libsass/subset_map.hpp +6 -4
  86. data/ext/libsass/to_c.hpp +4 -4
  87. data/ext/libsass/to_string.cpp +13 -8
  88. data/ext/libsass/to_string.hpp +6 -4
  89. data/ext/libsass/units.cpp +2 -1
  90. data/ext/libsass/units.hpp +6 -1
  91. data/ext/libsass/utf8_string.cpp +0 -5
  92. data/ext/libsass/utf8_string.hpp +3 -2
  93. data/ext/libsass/util.cpp +461 -49
  94. data/ext/libsass/util.hpp +34 -13
  95. data/ext/libsass/version.sh +10 -0
  96. data/ext/libsass/win/libsass.filters +20 -11
  97. data/ext/libsass/win/libsass.vcxproj +11 -8
  98. data/lib/sassc/importer.rb +1 -8
  99. data/lib/sassc/native.rb +7 -0
  100. data/lib/sassc/native/native_context_api.rb +5 -5
  101. data/lib/sassc/version.rb +1 -1
  102. data/test/native_test.rb +1 -1
  103. metadata +14 -10
  104. data/ext/libsass/copy_c_str.cpp +0 -13
  105. data/ext/libsass/copy_c_str.hpp +0 -5
  106. data/ext/libsass/output_compressed.cpp +0 -401
  107. data/ext/libsass/output_compressed.hpp +0 -95
  108. data/ext/libsass/output_nested.cpp +0 -364
  109. data/ext/libsass/output_nested.hpp +0 -108
  110. data/ext/libsass/test-driver +0 -127
  111. data/ext/libsass/token.hpp +0 -32
@@ -1,29 +1,15 @@
1
- #define SASS_PARSER
1
+ #ifndef SASS_PARSER_H
2
+ #define SASS_PARSER_H
2
3
 
3
- #include <vector>
4
4
  #include <map>
5
+ #include <vector>
6
+ #include <iostream>
5
7
 
6
- #ifndef SASS_PRELEXER
7
- #include "prelexer.hpp"
8
- #endif
9
-
10
- #ifndef SASS_TOKEN
11
- #include "token.hpp"
12
- #endif
13
-
14
- #ifndef SASS_CONTEXT
15
- #include "context.hpp"
16
- #endif
17
-
18
- #ifndef SASS_AST
19
8
  #include "ast.hpp"
20
- #endif
21
-
22
- #ifndef SASS_POSITION
23
9
  #include "position.hpp"
24
- #endif
25
-
26
- #include <iostream>
10
+ #include "context.hpp"
11
+ #include "position.hpp"
12
+ #include "prelexer.hpp"
27
13
 
28
14
  struct Selector_Lookahead {
29
15
  const char* found;
@@ -36,7 +22,7 @@ namespace Sass {
36
22
  using std::map;
37
23
  using namespace Prelexer;
38
24
 
39
- class Parser {
25
+ class Parser : public ParserState {
40
26
  private:
41
27
  void add_single_file (Import* imp, string import_path);
42
28
  public:
@@ -45,26 +31,30 @@ namespace Sass {
45
31
  enum Syntactic_Context { nothing, mixin_def, function_def };
46
32
 
47
33
  Context& ctx;
34
+ vector<Block*> block_stack;
48
35
  vector<Syntactic_Context> stack;
36
+ Media_Block* last_media_block;
49
37
  const char* source;
50
38
  const char* position;
51
39
  const char* end;
52
- string path;
53
- size_t column;
54
- Position source_position;
40
+ Position before_token;
41
+ Position after_token;
42
+ ParserState pstate;
43
+ int indentation;
55
44
 
56
45
 
57
46
  Token lexed;
58
- bool dequote;
47
+ bool in_at_root;
59
48
 
60
- Parser(Context& ctx, string path, Position source_position)
61
- : ctx(ctx), stack(vector<Syntactic_Context>()),
62
- source(0), position(0), end(0), path(path), column(1), source_position(source_position)
63
- { dequote = false; stack.push_back(nothing); }
49
+ Parser(Context& ctx, const ParserState& pstate)
50
+ : ParserState(pstate), ctx(ctx), block_stack(0), stack(0), last_media_block(0),
51
+ source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate("[NULL]"), indentation(0)
52
+ { in_at_root = false; stack.push_back(nothing); }
64
53
 
65
- static Parser from_string(string src, Context& ctx, string path = "", Position source_position = Position());
66
- static Parser from_c_str(const char* src, Context& ctx, string path = "", Position source_position = Position());
67
- static Parser from_token(Token t, Context& ctx, string path = "", Position source_position = Position());
54
+ // static Parser from_string(const string& src, Context& ctx, ParserState pstate = ParserState("[STRING]"));
55
+ static Parser from_c_str(const char* src, Context& ctx, ParserState pstate = ParserState("[CSTRING]"));
56
+ static Parser from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate = ParserState("[CSTRING]"));
57
+ static Parser from_token(Token t, Context& ctx, ParserState pstate = ParserState("[TOKEN]"));
68
58
 
69
59
  #ifdef __clang__
70
60
 
@@ -78,102 +68,141 @@ namespace Sass {
78
68
 
79
69
  #endif
80
70
 
71
+
72
+ bool peek_newline(const char* start = 0);
73
+
81
74
  template <prelexer mx>
82
75
  const char* peek(const char* start = 0)
83
76
  {
84
77
  if (!start) start = position;
85
- const char* after_whitespace;
78
+ const char* it_before_token;
86
79
  if (mx == block_comment) {
87
- after_whitespace = // start;
80
+ it_before_token = // start;
88
81
  zero_plus< alternatives<spaces, line_comment> >(start);
89
82
  }
90
83
  else if (/*mx == ancestor_of ||*/ mx == no_spaces) {
91
- after_whitespace = position;
84
+ it_before_token = position;
92
85
  }
93
- else if (mx == spaces || mx == ancestor_of) {
94
- after_whitespace = mx(start);
95
- if (after_whitespace) {
96
- return after_whitespace;
86
+ else if (mx == spaces) {
87
+ it_before_token = mx(start);
88
+ if (it_before_token) {
89
+ return it_before_token;
97
90
  }
98
91
  else {
99
92
  return 0;
100
93
  }
101
94
  }
102
95
  else if (mx == optional_spaces) {
103
- after_whitespace = optional_spaces(start);
96
+ it_before_token = optional_spaces(start);
104
97
  }
105
98
  else if (mx == line_comment_prefix || mx == block_comment_prefix) {
106
- after_whitespace = position;
99
+ it_before_token = position;
107
100
  }
108
101
  else {
109
- after_whitespace = spaces_and_comments(start);
102
+ it_before_token = optional_spaces_and_comments(start);
110
103
  }
111
- const char* after_token = mx(after_whitespace);
112
- if (after_token) {
113
- return after_token;
104
+ const char* it_after_token = mx(it_before_token);
105
+ if (it_after_token) {
106
+ return it_after_token;
114
107
  }
115
108
  else {
116
109
  return 0;
117
110
  }
118
111
  }
119
112
 
113
+ // white-space handling is built into the lexer
114
+ // this way you do not need to parse it yourself
115
+ // some matchers don't accept certain white-space
120
116
  template <prelexer mx>
121
117
  const char* lex()
122
118
  {
123
- const char* after_whitespace;
119
+
120
+ // remeber interesting position
121
+ const char* wspace_start = position;
122
+
123
+ // advance position for next call
124
+ before_token = after_token;
125
+
126
+ // after optional whitespace
127
+ const char* it_before_token;
128
+
124
129
  if (mx == block_comment) {
125
- after_whitespace = // position;
126
- zero_plus< alternatives<spaces, line_comment> >(position);
130
+ // a block comment can be preceded by spaces and/or line comments
131
+ it_before_token = zero_plus< alternatives<spaces, line_comment> >(position);
127
132
  }
128
- else if (mx == url) {
129
- after_whitespace = position;
130
- }
131
- else if (mx == ancestor_of || mx == no_spaces) {
132
- after_whitespace = position;
133
+ else if (mx == url || mx == no_spaces) {
134
+ // parse everything literally
135
+ it_before_token = position;
133
136
  }
137
+
134
138
  else if (mx == spaces) {
135
- after_whitespace = spaces(position);
136
- if (after_whitespace) {
137
- source_position.line += count_interval<'\n'>(position, after_whitespace);
138
- lexed = Token(position, after_whitespace);
139
- return position = after_whitespace;
139
+ it_before_token = spaces(position);
140
+ if (it_before_token) {
141
+ return position = it_before_token;
140
142
  }
141
143
  else {
142
144
  return 0;
143
145
  }
144
146
  }
147
+
148
+ else if (mx == optional_spaces_and_comments) {
149
+ it_before_token = position;
150
+ }
151
+ else if (mx == spaces_and_comments) {
152
+ it_before_token = position;
153
+ }
154
+
145
155
  else if (mx == optional_spaces) {
146
- after_whitespace = optional_spaces(position);
156
+ // ToDo: what are optiona_spaces ???
157
+ it_before_token = optional_spaces(position);
147
158
  }
148
159
  else {
149
- after_whitespace = spaces_and_comments(position);
160
+ // most can be preceded by spaces and comments
161
+ it_before_token = optional_spaces_and_comments(position);
150
162
  }
151
- const char* after_token = mx(after_whitespace);
152
- if (after_token) {
153
- size_t previous_line = source_position.line;
154
- source_position.line += count_interval<'\n'>(position, after_token);
155
-
156
- size_t whitespace = 0;
157
- const char* ptr = after_whitespace - 1;
158
- while (ptr >= position) {
159
- if (*ptr == '\n')
160
- break;
161
- whitespace++;
162
- ptr--;
163
- }
164
- if (previous_line != source_position.line) {
165
- column = 1;
163
+
164
+ // now call matcher to get position after token
165
+ const char* it_after_token = mx(it_before_token);
166
+ // assertion that we got a valid match
167
+ if (it_after_token == 0) return 0;
168
+
169
+ // add whitespace after previous and before this token
170
+ while (position < it_before_token && *position) {
171
+ if (*position == '\n') {
172
+ ++ before_token.line;
173
+ before_token.column = 0;
174
+ } else {
175
+ ++ before_token.column;
166
176
  }
177
+ ++position;
178
+ }
167
179
 
168
- source_position.column = column + whitespace;
169
- column += after_token - after_whitespace + whitespace;
170
- lexed = Token(after_whitespace, after_token);
180
+ // copy position
181
+ after_token = before_token;
171
182
 
172
- return position = after_token;
173
- }
174
- else {
175
- return 0;
183
+ Offset size(0, 0);
184
+
185
+ // increase position to include current token
186
+ while (position < it_after_token && *position) {
187
+ if (*position == '\n') {
188
+ ++ size.line;
189
+ size.column = 0;
190
+ } else {
191
+ ++ size.column;
192
+ }
193
+ ++position;
176
194
  }
195
+
196
+ after_token = after_token + size;
197
+
198
+ // create parsed token string (public member)
199
+ lexed = Token(wspace_start, it_before_token, it_after_token, optional_spaces_and_comments(it_after_token) ? optional_spaces_and_comments(it_after_token) : it_after_token, before_token);
200
+ Position pos(before_token.file, before_token.line, before_token.column);
201
+ pstate = ParserState(path, lexed, pos, size);
202
+
203
+ // advance internal char iterator
204
+ return position = it_after_token;
205
+
177
206
  }
178
207
 
179
208
  #ifdef __clang__
@@ -182,7 +211,7 @@ namespace Sass {
182
211
 
183
212
  #endif
184
213
 
185
- void error(string msg, Position pos = Position());
214
+ void error(string msg, Position pos);
186
215
  void read_bom();
187
216
 
188
217
  Block* parse();
@@ -194,7 +223,7 @@ namespace Sass {
194
223
  Arguments* parse_arguments();
195
224
  Argument* parse_argument();
196
225
  Assignment* parse_assignment();
197
- Propset* parse_propset();
226
+ // Propset* parse_propset();
198
227
  Ruleset* parse_ruleset(Selector_Lookahead lookahead);
199
228
  Selector_Schema* parse_selector_schema(const char* end_of_selector);
200
229
  Selector_List* parse_selector_group();
@@ -205,6 +234,7 @@ namespace Sass {
205
234
  Simple_Selector* parse_pseudo_selector();
206
235
  Attribute_Selector* parse_attribute_selector();
207
236
  Block* parse_block();
237
+ bool parse_number_prefix();
208
238
  Declaration* parse_declaration();
209
239
  Expression* parse_map_value();
210
240
  Expression* parse_map();
@@ -221,14 +251,14 @@ namespace Sass {
221
251
  Function_Call* parse_calc_function();
222
252
  Function_Call* parse_function_call();
223
253
  Function_Call_Schema* parse_function_call_schema();
224
- String* parse_interpolated_chunk(Token);
254
+ String* parse_interpolated_chunk(Token, bool constant = false);
225
255
  String* parse_string();
226
256
  String_Constant* parse_static_value();
227
257
  String* parse_ie_property();
228
258
  String* parse_ie_keyword_arg();
229
- String_Schema* parse_value_schema();
259
+ String_Schema* parse_value_schema(const char* stop);
230
260
  String* parse_identifier_schema();
231
- String_Schema* parse_url_schema();
261
+ // String_Schema* parse_url_schema();
232
262
  If* parse_if_directive(bool else_if = false);
233
263
  For* parse_for_directive();
234
264
  Each* parse_each_directive();
@@ -245,6 +275,8 @@ namespace Sass {
245
275
  Feature_Query_Condition* parse_supports_conjunction();
246
276
  Feature_Query_Condition* parse_supports_disjunction();
247
277
  Feature_Query_Condition* parse_supports_declaration();
278
+ At_Root_Block* parse_at_root_block();
279
+ At_Root_Expression* parse_at_root_expression();
248
280
  At_Rule* parse_at_rule();
249
281
  Warning* parse_warning();
250
282
  Error* parse_error();
@@ -262,3 +294,5 @@ namespace Sass {
262
294
 
263
295
  size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len);
264
296
  }
297
+
298
+ #endif
@@ -1,7 +1,10 @@
1
- #include <vector>
2
- #include <iostream>
1
+ #ifndef SASS_PATHS_H
2
+ #define SASS_PATHS_H
3
+
3
4
  #include <string>
5
+ #include <vector>
4
6
  #include <sstream>
7
+ #include <iostream>
5
8
 
6
9
  using namespace std;
7
10
 
@@ -67,3 +70,5 @@ namespace Sass {
67
70
  }
68
71
 
69
72
  }
73
+
74
+ #endif
@@ -0,0 +1,155 @@
1
+ #ifdef _WIN32
2
+ #include <windows.h>
3
+ #else
4
+ #include <sys/types.h>
5
+ #include <dirent.h>
6
+ #include <errno.h>
7
+ #include <dlfcn.h>
8
+ #endif
9
+
10
+ #include <iostream>
11
+ #include "output.hpp"
12
+ #include "plugins.hpp"
13
+
14
+ #define npos string::npos
15
+
16
+ namespace Sass {
17
+
18
+ Plugins::Plugins(void) { }
19
+ Plugins::~Plugins(void) { }
20
+
21
+ // check if plugin is compatible with this version
22
+ // plugins may be linked static against libsass
23
+ // we try to be compatible between major versions
24
+ inline bool compatibility(const char* their_version)
25
+ {
26
+ // const char* their_version = "3.1.2";
27
+ // first check if anyone has an unknown version
28
+ const char* our_version = libsass_version();
29
+ if (!strcmp(their_version, "[na]")) return false;
30
+ if (!strcmp(our_version, "[na]")) return false;
31
+
32
+ // find the position of the second dot
33
+ size_t pos = string(our_version).find('.', 0);
34
+ if (pos != npos) pos = string(our_version).find('.', pos + 1);
35
+
36
+ // if we do not have two dots we fallback to compare complete string
37
+ if (pos == npos) { return strcmp(their_version, our_version) ? 0 : 1; }
38
+ // otherwise only compare up to the second dot (major versions)
39
+ else { return strncmp(their_version, our_version, pos) ? 0 : 1; }
40
+
41
+ }
42
+
43
+ // load one specific plugin
44
+ bool Plugins::load_plugin (const string& path)
45
+ {
46
+
47
+ typedef const char* (*__plugin_version__)(void);
48
+ typedef Sass_C_Function_List (*__plugin_load_fns__)(void);
49
+
50
+ if (LOAD_LIB(plugin, path))
51
+ {
52
+ // try to load initial function to query libsass version suppor
53
+ if (LOAD_LIB_FN(__plugin_version__, plugin_version, "libsass_get_version"))
54
+ {
55
+ // get the libsass version of the plugin
56
+ if (!compatibility(plugin_version())) return false;
57
+ // try to get import address for "libsass_load_functions"
58
+ if (LOAD_LIB_FN(__plugin_load_fns__, plugin_load_functions, "libsass_load_functions"))
59
+ {
60
+ Sass_C_Function_List fns = plugin_load_functions();
61
+ while (fns && *fns) { functions.push_back(*fns); ++ fns; }
62
+ }
63
+ // success
64
+ return true;
65
+ }
66
+ else
67
+ {
68
+ // print debug message to stderr (should not happen)
69
+ cerr << "failed loading 'libsass_support' in <" << path << ">" << endl;
70
+ if (const char* dlsym_error = dlerror()) cerr << dlsym_error << endl;
71
+ CLOSE_LIB(plugin);
72
+ }
73
+ }
74
+ else
75
+ {
76
+ // print debug message to stderr (should not happen)
77
+ cerr << "failed loading plugin <" << path << ">" << endl;
78
+ if (const char* dlopen_error = dlerror()) cerr << dlopen_error << endl;
79
+ }
80
+
81
+ return false;
82
+
83
+ }
84
+
85
+ size_t Plugins::load_plugins(const string& path)
86
+ {
87
+
88
+ // count plugins
89
+ size_t loaded = 0;
90
+
91
+ #ifdef _WIN32
92
+
93
+ try
94
+ {
95
+
96
+ // use wchar (utf16)
97
+ WIN32_FIND_DATAW data;
98
+ // trailing slash is guaranteed
99
+ string globsrch(path + "*.dll");
100
+ // convert to wide chars (utf16) for system call
101
+ wstring wglobsrch(UTF_8::convert_to_utf16(globsrch));
102
+ HANDLE hFile = FindFirstFileW(wglobsrch.c_str(), &data);
103
+ // check if system called returned a result
104
+ // ToDo: maybe we should print a debug message
105
+ if (hFile == INVALID_HANDLE_VALUE) return -1;
106
+
107
+ // read directory
108
+ while (true)
109
+ {
110
+ try
111
+ {
112
+ // the system will report the filenames with wide chars (utf16)
113
+ string entry = UTF_8::convert_from_utf16(data.cFileName);
114
+ // check if file ending matches exactly
115
+ if (!ends_with(entry, ".dll")) continue;
116
+ // load the plugin and increase counter
117
+ if (load_plugin(path + entry)) ++ loaded;
118
+ // check if there should be more entries
119
+ if (GetLastError() == ERROR_NO_MORE_FILES) break;
120
+ // load next entry (check for return type)
121
+ if (!FindNextFileW(hFile, &data)) break;
122
+ }
123
+ catch (...)
124
+ {
125
+ // report the error to the console (should not happen)
126
+ // seems like we got strange data from the system call?
127
+ cerr << "filename in plugin path has invalid utf8?" << endl;
128
+ }
129
+ }
130
+ }
131
+ catch (utf8::invalid_utf8)
132
+ {
133
+ // report the error to the console (should not happen)
134
+ // implementors should make sure to provide valid utf8
135
+ cerr << "plugin path contains invalid utf8" << endl;
136
+ }
137
+
138
+ #else
139
+
140
+ DIR *dp;
141
+ struct dirent *dirp;
142
+ if((dp = opendir(path.c_str())) == NULL) return -1;
143
+ while ((dirp = readdir(dp)) != NULL) {
144
+ if (!ends_with(dirp->d_name, ".so")) continue;
145
+ if (load_plugin(path + dirp->d_name)) ++ loaded;
146
+ }
147
+ closedir(dp);
148
+
149
+ #endif
150
+ return loaded;
151
+
152
+ }
153
+
154
+ }
155
+