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