precompiled-sassc 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/cibuildgem.yaml +67 -0
  3. data/.gitignore +18 -0
  4. data/.gitmodules +3 -0
  5. data/.travis.yml +16 -0
  6. data/CHANGELOG.md +97 -0
  7. data/CODE_OF_CONDUCT.md +10 -0
  8. data/Gemfile +2 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +80 -0
  11. data/Rakefile +51 -0
  12. data/ext/depend +4 -0
  13. data/ext/extconf.rb +92 -0
  14. data/ext/libsass/VERSION +1 -0
  15. data/ext/libsass/contrib/plugin.cpp +60 -0
  16. data/ext/libsass/include/sass/base.h +97 -0
  17. data/ext/libsass/include/sass/context.h +174 -0
  18. data/ext/libsass/include/sass/functions.h +139 -0
  19. data/ext/libsass/include/sass/values.h +145 -0
  20. data/ext/libsass/include/sass/version.h +12 -0
  21. data/ext/libsass/include/sass.h +15 -0
  22. data/ext/libsass/include/sass2scss.h +120 -0
  23. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  24. data/ext/libsass/src/ast.cpp +953 -0
  25. data/ext/libsass/src/ast.hpp +1064 -0
  26. data/ext/libsass/src/ast2c.cpp +80 -0
  27. data/ext/libsass/src/ast2c.hpp +39 -0
  28. data/ext/libsass/src/ast_def_macros.hpp +140 -0
  29. data/ext/libsass/src/ast_fwd_decl.cpp +31 -0
  30. data/ext/libsass/src/ast_fwd_decl.hpp +274 -0
  31. data/ext/libsass/src/ast_helpers.hpp +292 -0
  32. data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
  33. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  34. data/ext/libsass/src/ast_sel_unify.cpp +275 -0
  35. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  36. data/ext/libsass/src/ast_selectors.cpp +1043 -0
  37. data/ext/libsass/src/ast_selectors.hpp +522 -0
  38. data/ext/libsass/src/ast_supports.cpp +114 -0
  39. data/ext/libsass/src/ast_supports.hpp +121 -0
  40. data/ext/libsass/src/ast_values.cpp +1154 -0
  41. data/ext/libsass/src/ast_values.hpp +498 -0
  42. data/ext/libsass/src/b64/cencode.h +32 -0
  43. data/ext/libsass/src/b64/encode.h +79 -0
  44. data/ext/libsass/src/backtrace.cpp +50 -0
  45. data/ext/libsass/src/backtrace.hpp +29 -0
  46. data/ext/libsass/src/base64vlq.cpp +47 -0
  47. data/ext/libsass/src/base64vlq.hpp +30 -0
  48. data/ext/libsass/src/bind.cpp +312 -0
  49. data/ext/libsass/src/bind.hpp +15 -0
  50. data/ext/libsass/src/c2ast.cpp +64 -0
  51. data/ext/libsass/src/c2ast.hpp +14 -0
  52. data/ext/libsass/src/c99func.c +54 -0
  53. data/ext/libsass/src/cencode.c +106 -0
  54. data/ext/libsass/src/check_nesting.cpp +393 -0
  55. data/ext/libsass/src/check_nesting.hpp +70 -0
  56. data/ext/libsass/src/color_maps.cpp +652 -0
  57. data/ext/libsass/src/color_maps.hpp +323 -0
  58. data/ext/libsass/src/constants.cpp +199 -0
  59. data/ext/libsass/src/constants.hpp +200 -0
  60. data/ext/libsass/src/context.cpp +863 -0
  61. data/ext/libsass/src/context.hpp +140 -0
  62. data/ext/libsass/src/cssize.cpp +521 -0
  63. data/ext/libsass/src/cssize.hpp +71 -0
  64. data/ext/libsass/src/dart_helpers.hpp +199 -0
  65. data/ext/libsass/src/debug.hpp +43 -0
  66. data/ext/libsass/src/debugger.hpp +963 -0
  67. data/ext/libsass/src/emitter.cpp +297 -0
  68. data/ext/libsass/src/emitter.hpp +101 -0
  69. data/ext/libsass/src/environment.cpp +260 -0
  70. data/ext/libsass/src/environment.hpp +124 -0
  71. data/ext/libsass/src/error_handling.cpp +233 -0
  72. data/ext/libsass/src/error_handling.hpp +239 -0
  73. data/ext/libsass/src/eval.cpp +1543 -0
  74. data/ext/libsass/src/eval.hpp +110 -0
  75. data/ext/libsass/src/eval_selectors.cpp +75 -0
  76. data/ext/libsass/src/expand.cpp +875 -0
  77. data/ext/libsass/src/expand.hpp +98 -0
  78. data/ext/libsass/src/extender.cpp +1188 -0
  79. data/ext/libsass/src/extender.hpp +399 -0
  80. data/ext/libsass/src/extension.cpp +43 -0
  81. data/ext/libsass/src/extension.hpp +89 -0
  82. data/ext/libsass/src/file.cpp +531 -0
  83. data/ext/libsass/src/file.hpp +124 -0
  84. data/ext/libsass/src/fn_colors.cpp +596 -0
  85. data/ext/libsass/src/fn_colors.hpp +85 -0
  86. data/ext/libsass/src/fn_lists.cpp +285 -0
  87. data/ext/libsass/src/fn_lists.hpp +34 -0
  88. data/ext/libsass/src/fn_maps.cpp +94 -0
  89. data/ext/libsass/src/fn_maps.hpp +30 -0
  90. data/ext/libsass/src/fn_miscs.cpp +244 -0
  91. data/ext/libsass/src/fn_miscs.hpp +40 -0
  92. data/ext/libsass/src/fn_numbers.cpp +227 -0
  93. data/ext/libsass/src/fn_numbers.hpp +45 -0
  94. data/ext/libsass/src/fn_selectors.cpp +205 -0
  95. data/ext/libsass/src/fn_selectors.hpp +35 -0
  96. data/ext/libsass/src/fn_strings.cpp +268 -0
  97. data/ext/libsass/src/fn_strings.hpp +34 -0
  98. data/ext/libsass/src/fn_utils.cpp +158 -0
  99. data/ext/libsass/src/fn_utils.hpp +62 -0
  100. data/ext/libsass/src/inspect.cpp +1125 -0
  101. data/ext/libsass/src/inspect.hpp +101 -0
  102. data/ext/libsass/src/json.cpp +1436 -0
  103. data/ext/libsass/src/json.hpp +117 -0
  104. data/ext/libsass/src/kwd_arg_macros.hpp +28 -0
  105. data/ext/libsass/src/lexer.cpp +122 -0
  106. data/ext/libsass/src/lexer.hpp +304 -0
  107. data/ext/libsass/src/listize.cpp +70 -0
  108. data/ext/libsass/src/listize.hpp +37 -0
  109. data/ext/libsass/src/mapping.hpp +19 -0
  110. data/ext/libsass/src/memory/allocator.cpp +48 -0
  111. data/ext/libsass/src/memory/allocator.hpp +138 -0
  112. data/ext/libsass/src/memory/config.hpp +20 -0
  113. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  114. data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
  115. data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
  116. data/ext/libsass/src/memory.hpp +12 -0
  117. data/ext/libsass/src/operation.hpp +223 -0
  118. data/ext/libsass/src/operators.cpp +267 -0
  119. data/ext/libsass/src/operators.hpp +30 -0
  120. data/ext/libsass/src/ordered_map.hpp +112 -0
  121. data/ext/libsass/src/output.cpp +320 -0
  122. data/ext/libsass/src/output.hpp +47 -0
  123. data/ext/libsass/src/parser.cpp +2965 -0
  124. data/ext/libsass/src/parser.hpp +394 -0
  125. data/ext/libsass/src/parser_selectors.cpp +189 -0
  126. data/ext/libsass/src/permutate.hpp +164 -0
  127. data/ext/libsass/src/plugins.cpp +188 -0
  128. data/ext/libsass/src/plugins.hpp +57 -0
  129. data/ext/libsass/src/position.cpp +165 -0
  130. data/ext/libsass/src/position.hpp +147 -0
  131. data/ext/libsass/src/prelexer.cpp +1780 -0
  132. data/ext/libsass/src/prelexer.hpp +484 -0
  133. data/ext/libsass/src/remove_placeholders.cpp +86 -0
  134. data/ext/libsass/src/remove_placeholders.hpp +37 -0
  135. data/ext/libsass/src/sass.cpp +156 -0
  136. data/ext/libsass/src/sass.hpp +147 -0
  137. data/ext/libsass/src/sass2scss.cpp +895 -0
  138. data/ext/libsass/src/sass_context.cpp +741 -0
  139. data/ext/libsass/src/sass_context.hpp +129 -0
  140. data/ext/libsass/src/sass_functions.cpp +210 -0
  141. data/ext/libsass/src/sass_functions.hpp +50 -0
  142. data/ext/libsass/src/sass_values.cpp +362 -0
  143. data/ext/libsass/src/sass_values.hpp +82 -0
  144. data/ext/libsass/src/settings.hpp +19 -0
  145. data/ext/libsass/src/source.cpp +69 -0
  146. data/ext/libsass/src/source.hpp +95 -0
  147. data/ext/libsass/src/source_data.hpp +32 -0
  148. data/ext/libsass/src/source_map.cpp +202 -0
  149. data/ext/libsass/src/source_map.hpp +65 -0
  150. data/ext/libsass/src/stylesheet.cpp +22 -0
  151. data/ext/libsass/src/stylesheet.hpp +57 -0
  152. data/ext/libsass/src/to_value.cpp +114 -0
  153. data/ext/libsass/src/to_value.hpp +46 -0
  154. data/ext/libsass/src/units.cpp +507 -0
  155. data/ext/libsass/src/units.hpp +110 -0
  156. data/ext/libsass/src/utf8/checked.h +336 -0
  157. data/ext/libsass/src/utf8/core.h +332 -0
  158. data/ext/libsass/src/utf8/unchecked.h +235 -0
  159. data/ext/libsass/src/utf8.h +34 -0
  160. data/ext/libsass/src/utf8_string.cpp +104 -0
  161. data/ext/libsass/src/utf8_string.hpp +38 -0
  162. data/ext/libsass/src/util.cpp +723 -0
  163. data/ext/libsass/src/util.hpp +105 -0
  164. data/ext/libsass/src/util_string.cpp +125 -0
  165. data/ext/libsass/src/util_string.hpp +73 -0
  166. data/ext/libsass/src/values.cpp +140 -0
  167. data/ext/libsass/src/values.hpp +12 -0
  168. data/lib/sassc/dependency.rb +17 -0
  169. data/lib/sassc/engine.rb +141 -0
  170. data/lib/sassc/error.rb +37 -0
  171. data/lib/sassc/functions_handler.rb +73 -0
  172. data/lib/sassc/import_handler.rb +50 -0
  173. data/lib/sassc/importer.rb +31 -0
  174. data/lib/sassc/native/native_context_api.rb +147 -0
  175. data/lib/sassc/native/native_functions_api.rb +159 -0
  176. data/lib/sassc/native/sass2scss_api.rb +10 -0
  177. data/lib/sassc/native/sass_input_style.rb +13 -0
  178. data/lib/sassc/native/sass_output_style.rb +12 -0
  179. data/lib/sassc/native/sass_value.rb +97 -0
  180. data/lib/sassc/native/string_list.rb +10 -0
  181. data/lib/sassc/native.rb +65 -0
  182. data/lib/sassc/sass_2_scss.rb +9 -0
  183. data/lib/sassc/script/functions.rb +8 -0
  184. data/lib/sassc/script/value/bool.rb +32 -0
  185. data/lib/sassc/script/value/color.rb +95 -0
  186. data/lib/sassc/script/value/list.rb +136 -0
  187. data/lib/sassc/script/value/map.rb +69 -0
  188. data/lib/sassc/script/value/number.rb +389 -0
  189. data/lib/sassc/script/value/string.rb +96 -0
  190. data/lib/sassc/script/value.rb +137 -0
  191. data/lib/sassc/script/value_conversion/base.rb +13 -0
  192. data/lib/sassc/script/value_conversion/bool.rb +13 -0
  193. data/lib/sassc/script/value_conversion/color.rb +18 -0
  194. data/lib/sassc/script/value_conversion/list.rb +25 -0
  195. data/lib/sassc/script/value_conversion/map.rb +21 -0
  196. data/lib/sassc/script/value_conversion/number.rb +13 -0
  197. data/lib/sassc/script/value_conversion/string.rb +17 -0
  198. data/lib/sassc/script/value_conversion.rb +69 -0
  199. data/lib/sassc/script.rb +17 -0
  200. data/lib/sassc/util/normalized_map.rb +117 -0
  201. data/lib/sassc/util.rb +231 -0
  202. data/lib/sassc/version.rb +5 -0
  203. data/lib/sassc.rb +57 -0
  204. data/sassc.gemspec +69 -0
  205. data/test/custom_importer_test.rb +127 -0
  206. data/test/engine_test.rb +314 -0
  207. data/test/error_test.rb +29 -0
  208. data/test/fixtures/paths.scss +10 -0
  209. data/test/functions_test.rb +340 -0
  210. data/test/native_test.rb +213 -0
  211. data/test/output_style_test.rb +107 -0
  212. data/test/sass_2_scss_test.rb +14 -0
  213. data/test/test_helper.rb +45 -0
  214. metadata +391 -0
@@ -0,0 +1,741 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+ #include "ast.hpp"
5
+
6
+ #include "sass_functions.hpp"
7
+ #include "json.hpp"
8
+
9
+ #define LFEED "\n"
10
+
11
+ // C++ helper
12
+ namespace Sass {
13
+ // see sass_copy_c_string(sass::string str)
14
+ static inline JsonNode* json_mkstream(const sass::ostream& stream)
15
+ {
16
+ // hold on to string on stack!
17
+ sass::string str(stream.str());
18
+ return json_mkstring(str.c_str());
19
+ }
20
+
21
+ static void handle_string_error(Sass_Context* c_ctx, const sass::string& msg, int severety)
22
+ {
23
+ sass::ostream msg_stream;
24
+ JsonNode* json_err = json_mkobject();
25
+ msg_stream << "Internal Error: " << msg << std::endl;
26
+ json_append_member(json_err, "status", json_mknumber(severety));
27
+ json_append_member(json_err, "message", json_mkstring(msg.c_str()));
28
+ json_append_member(json_err, "formatted", json_mkstream(msg_stream));
29
+ try { c_ctx->error_json = json_stringify(json_err, " "); }
30
+ catch (...) {}
31
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
32
+ c_ctx->error_text = sass_copy_c_string(msg.c_str());
33
+ c_ctx->error_status = severety;
34
+ c_ctx->output_string = 0;
35
+ c_ctx->source_map_string = 0;
36
+ json_delete(json_err);
37
+ }
38
+
39
+ static int handle_error(Sass_Context* c_ctx) {
40
+ try {
41
+ throw;
42
+ }
43
+ catch (Exception::Base& e) {
44
+ sass::ostream msg_stream;
45
+ sass::string cwd(Sass::File::get_cwd());
46
+ sass::string msg_prefix(e.errtype());
47
+ bool got_newline = false;
48
+ msg_stream << msg_prefix << ": ";
49
+ const char* msg = e.what();
50
+ while (msg && *msg) {
51
+ if (*msg == '\r') {
52
+ got_newline = true;
53
+ }
54
+ else if (*msg == '\n') {
55
+ got_newline = true;
56
+ }
57
+ else if (got_newline) {
58
+ msg_stream << sass::string(msg_prefix.size() + 2, ' ');
59
+ got_newline = false;
60
+ }
61
+ msg_stream << *msg;
62
+ ++msg;
63
+ }
64
+ if (!got_newline) msg_stream << "\n";
65
+
66
+ if (e.traces.empty()) {
67
+ // we normally should have some traces, still here as a fallback
68
+ sass::string rel_path(Sass::File::abs2rel(e.pstate.getPath(), cwd, cwd));
69
+ msg_stream << sass::string(msg_prefix.size() + 2, ' ');
70
+ msg_stream << " on line " << e.pstate.getLine() << " of " << rel_path << "\n";
71
+ }
72
+ else {
73
+ sass::string rel_path(Sass::File::abs2rel(e.pstate.getPath(), cwd, cwd));
74
+ msg_stream << traces_to_string(e.traces, " ");
75
+ }
76
+
77
+ // now create the code trace (ToDo: maybe have util functions?)
78
+ if (e.pstate.position.line != sass::string::npos &&
79
+ e.pstate.position.column != sass::string::npos &&
80
+ e.pstate.source != nullptr) {
81
+ Offset offset(e.pstate.position);
82
+ size_t lines = offset.line;
83
+ // scan through src until target line
84
+ // move line_beg pointer to line start
85
+ const char* line_beg;
86
+ for (line_beg = e.pstate.getRawData(); *line_beg != '\0'; ++line_beg) {
87
+ if (lines == 0) break;
88
+ if (*line_beg == '\n') --lines;
89
+ }
90
+ // move line_end before next newline character
91
+ const char* line_end;
92
+ for (line_end = line_beg; *line_end != '\0'; ++line_end) {
93
+ if (*line_end == '\n' || *line_end == '\r') break;
94
+ }
95
+ if (*line_end != '\0') ++line_end;
96
+ size_t line_len = line_end - line_beg;
97
+ size_t move_in = 0; size_t shorten = 0;
98
+ size_t left_chars = 42; size_t max_chars = 76;
99
+ // reported excerpt should not exceed `max_chars` chars
100
+ if (offset.column > line_len) left_chars = offset.column;
101
+ if (offset.column > left_chars) move_in = offset.column - left_chars;
102
+ if (line_len > max_chars + move_in) shorten = line_len - move_in - max_chars;
103
+ utf8::advance(line_beg, move_in, line_end);
104
+ utf8::retreat(line_end, shorten, line_beg);
105
+ sass::string sanitized; sass::string marker(offset.column - move_in, '-');
106
+ utf8::replace_invalid(line_beg, line_end, std::back_inserter(sanitized));
107
+ msg_stream << ">> " << sanitized << "\n";
108
+ msg_stream << " " << marker << "^\n";
109
+ }
110
+
111
+ JsonNode* json_err = json_mkobject();
112
+ json_append_member(json_err, "status", json_mknumber(1));
113
+ json_append_member(json_err, "file", json_mkstring(e.pstate.getPath()));
114
+ json_append_member(json_err, "line", json_mknumber((double)(e.pstate.getLine())));
115
+ json_append_member(json_err, "column", json_mknumber((double)(e.pstate.getColumn())));
116
+ json_append_member(json_err, "message", json_mkstring(e.what()));
117
+ json_append_member(json_err, "formatted", json_mkstream(msg_stream));
118
+ try { c_ctx->error_json = json_stringify(json_err, " "); }
119
+ catch (...) {} // silently ignore this error?
120
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
121
+ c_ctx->error_text = sass_copy_c_string(e.what());
122
+ c_ctx->error_status = 1;
123
+ c_ctx->error_file = sass_copy_c_string(e.pstate.getPath());
124
+ c_ctx->error_line = e.pstate.getLine();
125
+ c_ctx->error_column = e.pstate.getColumn();
126
+ c_ctx->error_src = sass_copy_c_string(e.pstate.getRawData());
127
+ c_ctx->output_string = 0;
128
+ c_ctx->source_map_string = 0;
129
+ json_delete(json_err);
130
+ }
131
+ catch (std::bad_alloc& ba) {
132
+ sass::ostream msg_stream;
133
+ msg_stream << "Unable to allocate memory: " << ba.what();
134
+ handle_string_error(c_ctx, msg_stream.str(), 2);
135
+ }
136
+ catch (std::exception& e) {
137
+ handle_string_error(c_ctx, e.what(), 3);
138
+ }
139
+ catch (sass::string& e) {
140
+ handle_string_error(c_ctx, e, 4);
141
+ }
142
+ catch (const char* e) {
143
+ handle_string_error(c_ctx, e, 4);
144
+ }
145
+ catch (...) {
146
+ handle_string_error(c_ctx, "unknown", 5);
147
+ }
148
+ return c_ctx->error_status;
149
+ }
150
+
151
+ // allow one error handler to throw another error
152
+ // this can happen with invalid utf8 and json lib
153
+ static int handle_errors(Sass_Context* c_ctx) {
154
+ try { return handle_error(c_ctx); }
155
+ catch (...) { return handle_error(c_ctx); }
156
+ }
157
+
158
+ static Block_Obj sass_parse_block(Sass_Compiler* compiler) throw()
159
+ {
160
+
161
+ // assert valid pointer
162
+ if (compiler == 0) return {};
163
+ // The cpp context must be set by now
164
+ Context* cpp_ctx = compiler->cpp_ctx;
165
+ Sass_Context* c_ctx = compiler->c_ctx;
166
+ // We will take care to wire up the rest
167
+ compiler->cpp_ctx->c_compiler = compiler;
168
+ compiler->state = SASS_COMPILER_PARSED;
169
+
170
+ try {
171
+
172
+ // get input/output path from options
173
+ sass::string input_path = safe_str(c_ctx->input_path);
174
+ sass::string output_path = safe_str(c_ctx->output_path);
175
+
176
+ // maybe skip some entries of included files
177
+ // we do not include stdin for data contexts
178
+ bool skip = c_ctx->type == SASS_CONTEXT_DATA;
179
+
180
+ // dispatch parse call
181
+ Block_Obj root(cpp_ctx->parse());
182
+ // abort on errors
183
+ if (!root) return {};
184
+
185
+ // skip all prefixed files? (ToDo: check srcmap)
186
+ // IMO source-maps should point to headers already
187
+ // therefore don't skip it for now. re-enable or
188
+ // remove completely once this is tested
189
+ size_t headers = cpp_ctx->head_imports;
190
+
191
+ // copy the included files on to the context (dont forget to free later)
192
+ if (copy_strings(cpp_ctx->get_included_files(skip, headers), &c_ctx->included_files) == NULL)
193
+ throw(std::bad_alloc());
194
+
195
+ // return parsed block
196
+ return root;
197
+
198
+ }
199
+ // pass errors to generic error handler
200
+ catch (...) { handle_errors(c_ctx); }
201
+
202
+ // error
203
+ return {};
204
+
205
+ }
206
+
207
+ }
208
+
209
+ extern "C" {
210
+ using namespace Sass;
211
+
212
+ static void sass_clear_options (struct Sass_Options* options);
213
+ static void sass_reset_options (struct Sass_Options* options);
214
+ static void copy_options(struct Sass_Options* to, struct Sass_Options* from) {
215
+ // do not overwrite ourself
216
+ if (to == from) return;
217
+ // free assigned memory
218
+ sass_clear_options(to);
219
+ // move memory
220
+ *to = *from;
221
+ // Reset pointers on source
222
+ sass_reset_options(from);
223
+ }
224
+
225
+ #define IMPLEMENT_SASS_OPTION_ACCESSOR(type, option) \
226
+ type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return options->option; } \
227
+ void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) { options->option = option; }
228
+ #define IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \
229
+ type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return safe_str(options->option, def); }
230
+ #define IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def) \
231
+ void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) \
232
+ { free(options->option); options->option = option || def ? sass_copy_c_string(option ? option : def) : 0; }
233
+ #define IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(type, option, def) \
234
+ IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \
235
+ IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def)
236
+
237
+ #define IMPLEMENT_SASS_CONTEXT_GETTER(type, option) \
238
+ type ADDCALL sass_context_get_##option (struct Sass_Context* ctx) { return ctx->option; }
239
+ #define IMPLEMENT_SASS_CONTEXT_TAKER(type, option) \
240
+ type sass_context_take_##option (struct Sass_Context* ctx) \
241
+ { type foo = ctx->option; ctx->option = 0; return foo; }
242
+
243
+
244
+ // generic compilation function (not exported, use file/data compile instead)
245
+ static Sass_Compiler* sass_prepare_context (Sass_Context* c_ctx, Context* cpp_ctx) throw()
246
+ {
247
+ try {
248
+ // register our custom functions
249
+ if (c_ctx->c_functions) {
250
+ auto this_func_data = c_ctx->c_functions;
251
+ while (this_func_data && *this_func_data) {
252
+ cpp_ctx->add_c_function(*this_func_data);
253
+ ++this_func_data;
254
+ }
255
+ }
256
+
257
+ // register our custom headers
258
+ if (c_ctx->c_headers) {
259
+ auto this_head_data = c_ctx->c_headers;
260
+ while (this_head_data && *this_head_data) {
261
+ cpp_ctx->add_c_header(*this_head_data);
262
+ ++this_head_data;
263
+ }
264
+ }
265
+
266
+ // register our custom importers
267
+ if (c_ctx->c_importers) {
268
+ auto this_imp_data = c_ctx->c_importers;
269
+ while (this_imp_data && *this_imp_data) {
270
+ cpp_ctx->add_c_importer(*this_imp_data);
271
+ ++this_imp_data;
272
+ }
273
+ }
274
+
275
+ // reset error status
276
+ c_ctx->error_json = 0;
277
+ c_ctx->error_text = 0;
278
+ c_ctx->error_message = 0;
279
+ c_ctx->error_status = 0;
280
+ // reset error position
281
+ c_ctx->error_file = 0;
282
+ c_ctx->error_src = 0;
283
+ c_ctx->error_line = sass::string::npos;
284
+ c_ctx->error_column = sass::string::npos;
285
+
286
+ // allocate a new compiler instance
287
+ void* ctxmem = calloc(1, sizeof(struct Sass_Compiler));
288
+ if (ctxmem == 0) { std::cerr << "Error allocating memory for context" << std::endl; return 0; }
289
+ Sass_Compiler* compiler = (struct Sass_Compiler*) ctxmem;
290
+ compiler->state = SASS_COMPILER_CREATED;
291
+
292
+ // store in sass compiler
293
+ compiler->c_ctx = c_ctx;
294
+ compiler->cpp_ctx = cpp_ctx;
295
+ cpp_ctx->c_compiler = compiler;
296
+
297
+ // use to parse block
298
+ return compiler;
299
+
300
+ }
301
+ // pass errors to generic error handler
302
+ catch (...) { handle_errors(c_ctx); }
303
+
304
+ // error
305
+ return 0;
306
+
307
+ }
308
+
309
+ // generic compilation function (not exported, use file/data compile instead)
310
+ static int sass_compile_context (Sass_Context* c_ctx, Context* cpp_ctx)
311
+ {
312
+
313
+ // prepare sass compiler with context and options
314
+ Sass_Compiler* compiler = sass_prepare_context(c_ctx, cpp_ctx);
315
+
316
+ try {
317
+ // call each compiler step
318
+ sass_compiler_parse(compiler);
319
+ sass_compiler_execute(compiler);
320
+ }
321
+ // pass errors to generic error handler
322
+ catch (...) { handle_errors(c_ctx); }
323
+
324
+ sass_delete_compiler(compiler);
325
+
326
+ return c_ctx->error_status;
327
+ }
328
+
329
+ inline void init_options (struct Sass_Options* options)
330
+ {
331
+ options->precision = 10;
332
+ options->indent = " ";
333
+ options->linefeed = LFEED;
334
+ }
335
+
336
+ Sass_Options* ADDCALL sass_make_options (void)
337
+ {
338
+ struct Sass_Options* options = (struct Sass_Options*) calloc(1, sizeof(struct Sass_Options));
339
+ if (options == 0) { std::cerr << "Error allocating memory for options" << std::endl; return 0; }
340
+ init_options(options);
341
+ return options;
342
+ }
343
+
344
+ Sass_File_Context* ADDCALL sass_make_file_context(const char* input_path)
345
+ {
346
+ #ifdef DEBUG_SHARED_PTR
347
+ SharedObj::setTaint(true);
348
+ #endif
349
+ struct Sass_File_Context* ctx = (struct Sass_File_Context*) calloc(1, sizeof(struct Sass_File_Context));
350
+ if (ctx == 0) { std::cerr << "Error allocating memory for file context" << std::endl; return 0; }
351
+ ctx->type = SASS_CONTEXT_FILE;
352
+ init_options(ctx);
353
+ try {
354
+ if (input_path == 0) { throw(std::runtime_error("File context created without an input path")); }
355
+ if (*input_path == 0) { throw(std::runtime_error("File context created with empty input path")); }
356
+ sass_option_set_input_path(ctx, input_path);
357
+ } catch (...) {
358
+ handle_errors(ctx);
359
+ }
360
+ return ctx;
361
+ }
362
+
363
+ Sass_Data_Context* ADDCALL sass_make_data_context(char* source_string)
364
+ {
365
+ #ifdef DEBUG_SHARED_PTR
366
+ SharedObj::setTaint(true);
367
+ #endif
368
+ struct Sass_Data_Context* ctx = (struct Sass_Data_Context*) calloc(1, sizeof(struct Sass_Data_Context));
369
+ if (ctx == 0) { std::cerr << "Error allocating memory for data context" << std::endl; return 0; }
370
+ ctx->type = SASS_CONTEXT_DATA;
371
+ init_options(ctx);
372
+ try {
373
+ if (source_string == 0) { throw(std::runtime_error("Data context created without a source string")); }
374
+ if (*source_string == 0) { throw(std::runtime_error("Data context created with empty source string")); }
375
+ ctx->source_string = source_string;
376
+ } catch (...) {
377
+ handle_errors(ctx);
378
+ }
379
+ return ctx;
380
+ }
381
+
382
+ struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* data_ctx)
383
+ {
384
+ if (data_ctx == 0) return 0;
385
+ Context* cpp_ctx = new Data_Context(*data_ctx);
386
+ return sass_prepare_context(data_ctx, cpp_ctx);
387
+ }
388
+
389
+ struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* file_ctx)
390
+ {
391
+ if (file_ctx == 0) return 0;
392
+ Context* cpp_ctx = new File_Context(*file_ctx);
393
+ return sass_prepare_context(file_ctx, cpp_ctx);
394
+ }
395
+
396
+ int ADDCALL sass_compile_data_context(Sass_Data_Context* data_ctx)
397
+ {
398
+ if (data_ctx == 0) return 1;
399
+ if (data_ctx->error_status)
400
+ return data_ctx->error_status;
401
+ try {
402
+ if (data_ctx->source_string == 0) { throw(std::runtime_error("Data context has no source string")); }
403
+ // empty source string is a valid case, even if not really useful (different than with file context)
404
+ // if (*data_ctx->source_string == 0) { throw(std::runtime_error("Data context has empty source string")); }
405
+ }
406
+ catch (...) { return handle_errors(data_ctx) | 1; }
407
+ Context* cpp_ctx = new Data_Context(*data_ctx);
408
+ return sass_compile_context(data_ctx, cpp_ctx);
409
+ }
410
+
411
+ int ADDCALL sass_compile_file_context(Sass_File_Context* file_ctx)
412
+ {
413
+ if (file_ctx == 0) return 1;
414
+ if (file_ctx->error_status)
415
+ return file_ctx->error_status;
416
+ try {
417
+ if (file_ctx->input_path == 0) { throw(std::runtime_error("File context has no input path")); }
418
+ if (*file_ctx->input_path == 0) { throw(std::runtime_error("File context has empty input path")); }
419
+ }
420
+ catch (...) { return handle_errors(file_ctx) | 1; }
421
+ Context* cpp_ctx = new File_Context(*file_ctx);
422
+ return sass_compile_context(file_ctx, cpp_ctx);
423
+ }
424
+
425
+ int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler)
426
+ {
427
+ if (compiler == 0) return 1;
428
+ if (compiler->state == SASS_COMPILER_PARSED) return 0;
429
+ if (compiler->state != SASS_COMPILER_CREATED) return -1;
430
+ if (compiler->c_ctx == NULL) return 1;
431
+ if (compiler->cpp_ctx == NULL) return 1;
432
+ if (compiler->c_ctx->error_status)
433
+ return compiler->c_ctx->error_status;
434
+ // parse the context we have set up (file or data)
435
+ compiler->root = sass_parse_block(compiler);
436
+ // success
437
+ return 0;
438
+ }
439
+
440
+ int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler)
441
+ {
442
+ if (compiler == 0) return 1;
443
+ if (compiler->state == SASS_COMPILER_EXECUTED) return 0;
444
+ if (compiler->state != SASS_COMPILER_PARSED) return -1;
445
+ if (compiler->c_ctx == NULL) return 1;
446
+ if (compiler->cpp_ctx == NULL) return 1;
447
+ if (compiler->root.isNull()) return 1;
448
+ if (compiler->c_ctx->error_status)
449
+ return compiler->c_ctx->error_status;
450
+ compiler->state = SASS_COMPILER_EXECUTED;
451
+ Context* cpp_ctx = compiler->cpp_ctx;
452
+ Block_Obj root = compiler->root;
453
+ // compile the parsed root block
454
+ try { compiler->c_ctx->output_string = cpp_ctx->render(root); }
455
+ // pass catched errors to generic error handler
456
+ catch (...) { return handle_errors(compiler->c_ctx) | 1; }
457
+ // generate source map json and store on context
458
+ compiler->c_ctx->source_map_string = cpp_ctx->render_srcmap();
459
+ // success
460
+ return 0;
461
+ }
462
+
463
+ // helper function, not exported, only accessible locally
464
+ static void sass_reset_options (struct Sass_Options* options)
465
+ {
466
+ // free pointer before
467
+ // or copy/move them
468
+ options->input_path = 0;
469
+ options->output_path = 0;
470
+ options->plugin_path = 0;
471
+ options->include_path = 0;
472
+ options->source_map_file = 0;
473
+ options->source_map_root = 0;
474
+ options->c_functions = 0;
475
+ options->c_importers = 0;
476
+ options->c_headers = 0;
477
+ options->plugin_paths = 0;
478
+ options->include_paths = 0;
479
+ }
480
+
481
+ // helper function, not exported, only accessible locally
482
+ static void sass_clear_options (struct Sass_Options* options)
483
+ {
484
+ if (options == 0) return;
485
+ // Deallocate custom functions, headers and imports
486
+ sass_delete_function_list(options->c_functions);
487
+ sass_delete_importer_list(options->c_importers);
488
+ sass_delete_importer_list(options->c_headers);
489
+ // Deallocate inc paths
490
+ if (options->plugin_paths) {
491
+ struct string_list* cur;
492
+ struct string_list* next;
493
+ cur = options->plugin_paths;
494
+ while (cur) {
495
+ next = cur->next;
496
+ free(cur->string);
497
+ free(cur);
498
+ cur = next;
499
+ }
500
+ }
501
+ // Deallocate inc paths
502
+ if (options->include_paths) {
503
+ struct string_list* cur;
504
+ struct string_list* next;
505
+ cur = options->include_paths;
506
+ while (cur) {
507
+ next = cur->next;
508
+ free(cur->string);
509
+ free(cur);
510
+ cur = next;
511
+ }
512
+ }
513
+ // Free options strings
514
+ free(options->input_path);
515
+ free(options->output_path);
516
+ free(options->plugin_path);
517
+ free(options->include_path);
518
+ free(options->source_map_file);
519
+ free(options->source_map_root);
520
+ // Reset our pointers
521
+ options->input_path = 0;
522
+ options->output_path = 0;
523
+ options->plugin_path = 0;
524
+ options->include_path = 0;
525
+ options->source_map_file = 0;
526
+ options->source_map_root = 0;
527
+ options->c_functions = 0;
528
+ options->c_importers = 0;
529
+ options->c_headers = 0;
530
+ options->plugin_paths = 0;
531
+ options->include_paths = 0;
532
+ }
533
+
534
+ // helper function, not exported, only accessible locally
535
+ // sass_free_context is also defined in old sass_interface
536
+ static void sass_clear_context (struct Sass_Context* ctx)
537
+ {
538
+ if (ctx == 0) return;
539
+ // release the allocated memory (mostly via sass_copy_c_string)
540
+ if (ctx->output_string) free(ctx->output_string);
541
+ if (ctx->source_map_string) free(ctx->source_map_string);
542
+ if (ctx->error_message) free(ctx->error_message);
543
+ if (ctx->error_text) free(ctx->error_text);
544
+ if (ctx->error_json) free(ctx->error_json);
545
+ if (ctx->error_file) free(ctx->error_file);
546
+ if (ctx->error_src) free(ctx->error_src);
547
+ free_string_array(ctx->included_files);
548
+ // play safe and reset properties
549
+ ctx->output_string = 0;
550
+ ctx->source_map_string = 0;
551
+ ctx->error_message = 0;
552
+ ctx->error_text = 0;
553
+ ctx->error_json = 0;
554
+ ctx->error_file = 0;
555
+ ctx->error_src = 0;
556
+ ctx->included_files = 0;
557
+ // debug leaked memory
558
+ #ifdef DEBUG_SHARED_PTR
559
+ SharedObj::dumpMemLeaks();
560
+ #endif
561
+ // now clear the options
562
+ sass_clear_options(ctx);
563
+ }
564
+
565
+ void ADDCALL sass_delete_compiler (struct Sass_Compiler* compiler)
566
+ {
567
+ if (compiler == 0) {
568
+ return;
569
+ }
570
+ Context* cpp_ctx = compiler->cpp_ctx;
571
+ if (cpp_ctx) delete(cpp_ctx);
572
+ compiler->cpp_ctx = NULL;
573
+ compiler->c_ctx = NULL;
574
+ compiler->root = {};
575
+ free(compiler);
576
+ }
577
+
578
+ void ADDCALL sass_delete_options (struct Sass_Options* options)
579
+ {
580
+ sass_clear_options(options); free(options);
581
+ }
582
+
583
+ // Deallocate all associated memory with file context
584
+ void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx)
585
+ {
586
+ // clear the context and free it
587
+ sass_clear_context(ctx); free(ctx);
588
+ }
589
+ // Deallocate all associated memory with data context
590
+ void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx)
591
+ {
592
+ // clean the source string if it was not passed
593
+ // we reset this member once we start parsing
594
+ if (ctx->source_string) free(ctx->source_string);
595
+ // clear the context and free it
596
+ sass_clear_context(ctx); free(ctx);
597
+ }
598
+
599
+ // Getters for sass context from specific implementations
600
+ struct Sass_Context* ADDCALL sass_file_context_get_context(struct Sass_File_Context* ctx) { return ctx; }
601
+ struct Sass_Context* ADDCALL sass_data_context_get_context(struct Sass_Data_Context* ctx) { return ctx; }
602
+
603
+ // Getters for context options from Sass_Context
604
+ struct Sass_Options* ADDCALL sass_context_get_options(struct Sass_Context* ctx) { return ctx; }
605
+ struct Sass_Options* ADDCALL sass_file_context_get_options(struct Sass_File_Context* ctx) { return ctx; }
606
+ struct Sass_Options* ADDCALL sass_data_context_get_options(struct Sass_Data_Context* ctx) { return ctx; }
607
+ void ADDCALL sass_file_context_set_options (struct Sass_File_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
608
+ void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
609
+
610
+ // Getters for Sass_Compiler options (get connected sass context)
611
+ enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler) { return compiler->state; }
612
+ struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler) { return compiler->c_ctx; }
613
+ struct Sass_Options* ADDCALL sass_compiler_get_options(struct Sass_Compiler* compiler) { return compiler->c_ctx; }
614
+ // Getters for Sass_Compiler options (query import stack)
615
+ size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.size(); }
616
+ Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.back(); }
617
+ Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx) { return compiler->cpp_ctx->import_stack[idx]; }
618
+ // Getters for Sass_Compiler options (query function stack)
619
+ size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->callee_stack.size(); }
620
+ Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler) { return &compiler->cpp_ctx->callee_stack.back(); }
621
+ Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx) { return &compiler->cpp_ctx->callee_stack[idx]; }
622
+
623
+ // Calculate the size of the stored null terminated array
624
+ size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx)
625
+ { size_t l = 0; auto i = ctx->included_files; while (i && *i) { ++i; ++l; } return l; }
626
+
627
+ // Create getter and setters for options
628
+ IMPLEMENT_SASS_OPTION_ACCESSOR(int, precision);
629
+ IMPLEMENT_SASS_OPTION_ACCESSOR(enum Sass_Output_Style, output_style);
630
+ IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_comments);
631
+ IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_embed);
632
+ IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_contents);
633
+ IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_file_urls);
634
+ IMPLEMENT_SASS_OPTION_ACCESSOR(bool, omit_source_map_url);
635
+ IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src);
636
+ IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Function_List, c_functions);
637
+ IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_importers);
638
+ IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_headers);
639
+ IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, indent);
640
+ IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, linefeed);
641
+ IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, plugin_path, 0);
642
+ IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, include_path, 0);
643
+ IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, input_path, 0);
644
+ IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, output_path, 0);
645
+ IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_file, 0);
646
+ IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_root, 0);
647
+
648
+ // Create getter and setters for context
649
+ IMPLEMENT_SASS_CONTEXT_GETTER(int, error_status);
650
+ IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_json);
651
+ IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_message);
652
+ IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_text);
653
+ IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_file);
654
+ IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_src);
655
+ IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_line);
656
+ IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_column);
657
+ IMPLEMENT_SASS_CONTEXT_GETTER(const char*, output_string);
658
+ IMPLEMENT_SASS_CONTEXT_GETTER(const char*, source_map_string);
659
+ IMPLEMENT_SASS_CONTEXT_GETTER(char**, included_files);
660
+
661
+ // Take ownership of memory (value on context is set to 0)
662
+ IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_json);
663
+ IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_message);
664
+ IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_text);
665
+ IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_file);
666
+ IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_src);
667
+ IMPLEMENT_SASS_CONTEXT_TAKER(char*, output_string);
668
+ IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string);
669
+ IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files);
670
+
671
+ // Push function for include paths (no manipulation support for now)
672
+ void ADDCALL sass_option_push_include_path(struct Sass_Options* options, const char* path)
673
+ {
674
+
675
+ struct string_list* include_path = (struct string_list*) calloc(1, sizeof(struct string_list));
676
+ if (include_path == 0) return;
677
+ include_path->string = path ? sass_copy_c_string(path) : 0;
678
+ struct string_list* last = options->include_paths;
679
+ if (!options->include_paths) {
680
+ options->include_paths = include_path;
681
+ } else {
682
+ while (last->next)
683
+ last = last->next;
684
+ last->next = include_path;
685
+ }
686
+
687
+ }
688
+
689
+ // Push function for include paths (no manipulation support for now)
690
+ size_t ADDCALL sass_option_get_include_path_size(struct Sass_Options* options)
691
+ {
692
+ size_t len = 0;
693
+ struct string_list* cur = options->include_paths;
694
+ while (cur) { len ++; cur = cur->next; }
695
+ return len;
696
+ }
697
+
698
+ // Push function for include paths (no manipulation support for now)
699
+ const char* ADDCALL sass_option_get_include_path(struct Sass_Options* options, size_t i)
700
+ {
701
+ struct string_list* cur = options->include_paths;
702
+ while (i) { i--; cur = cur->next; }
703
+ return cur->string;
704
+ }
705
+
706
+ // Push function for plugin paths (no manipulation support for now)
707
+ size_t ADDCALL sass_option_get_plugin_path_size(struct Sass_Options* options)
708
+ {
709
+ size_t len = 0;
710
+ struct string_list* cur = options->plugin_paths;
711
+ while (cur) { len++; cur = cur->next; }
712
+ return len;
713
+ }
714
+
715
+ // Push function for plugin paths (no manipulation support for now)
716
+ const char* ADDCALL sass_option_get_plugin_path(struct Sass_Options* options, size_t i)
717
+ {
718
+ struct string_list* cur = options->plugin_paths;
719
+ while (i) { i--; cur = cur->next; }
720
+ return cur->string;
721
+ }
722
+
723
+ // Push function for plugin paths (no manipulation support for now)
724
+ void ADDCALL sass_option_push_plugin_path(struct Sass_Options* options, const char* path)
725
+ {
726
+
727
+ struct string_list* plugin_path = (struct string_list*) calloc(1, sizeof(struct string_list));
728
+ if (plugin_path == 0) return;
729
+ plugin_path->string = path ? sass_copy_c_string(path) : 0;
730
+ struct string_list* last = options->plugin_paths;
731
+ if (!options->plugin_paths) {
732
+ options->plugin_paths = plugin_path;
733
+ } else {
734
+ while (last->next)
735
+ last = last->next;
736
+ last->next = plugin_path;
737
+ }
738
+
739
+ }
740
+
741
+ }