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
12namespace 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(s: 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(object: json_err, key: "status", value: json_mknumber(n: severety));
27 json_append_member(object: json_err, key: "message", value: json_mkstring(s: msg.c_str()));
28 json_append_member(object: json_err, key: "formatted", value: json_mkstream(stream: msg_stream));
29 try { c_ctx->error_json = json_stringify(node: json_err, space: " "); }
30 catch (...) {}
31 c_ctx->error_message = sass_copy_string(str: msg_stream.str());
32 c_ctx->error_text = sass_copy_c_string(str: 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(node: 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(path: e.pstate.getPath(), base: 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(path: e.pstate.getPath(), base: cwd, cwd));
74 msg_stream << traces_to_string(traces: e.traces, indent: " ");
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(it&: line_beg, n: move_in, end: line_end);
104 utf8::retreat(it&: line_end, n: shorten, end: line_beg);
105 sass::string sanitized; sass::string marker(offset.column - move_in, '-');
106 utf8::replace_invalid(start: line_beg, end: line_end, out: std::back_inserter(x&: sanitized));
107 msg_stream << ">> " << sanitized << "\n";
108 msg_stream << " " << marker << "^\n";
109 }
110
111 JsonNode* json_err = json_mkobject();
112 json_append_member(object: json_err, key: "status", value: json_mknumber(n: 1));
113 json_append_member(object: json_err, key: "file", value: json_mkstring(s: e.pstate.getPath()));
114 json_append_member(object: json_err, key: "line", value: json_mknumber(n: (double)(e.pstate.getLine())));
115 json_append_member(object: json_err, key: "column", value: json_mknumber(n: (double)(e.pstate.getColumn())));
116 json_append_member(object: json_err, key: "message", value: json_mkstring(s: e.what()));
117 json_append_member(object: json_err, key: "formatted", value: json_mkstream(stream: msg_stream));
118 try { c_ctx->error_json = json_stringify(node: json_err, space: " "); }
119 catch (...) {} // silently ignore this error?
120 c_ctx->error_message = sass_copy_string(str: msg_stream.str());
121 c_ctx->error_text = sass_copy_c_string(str: e.what());
122 c_ctx->error_status = 1;
123 c_ctx->error_file = sass_copy_c_string(str: 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(str: e.pstate.getRawData());
127 c_ctx->output_string = 0;
128 c_ctx->source_map_string = 0;
129 json_delete(node: 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: msg_stream.str(), severety: 2);
135 }
136 catch (std::exception& e) {
137 handle_string_error(c_ctx, msg: e.what(), severety: 3);
138 }
139 catch (sass::string& e) {
140 handle_string_error(c_ctx, msg: e, severety: 4);
141 }
142 catch (const char* e) {
143 handle_string_error(c_ctx, msg: e, severety: 4);
144 }
145 catch (...) {
146 handle_string_error(c_ctx, msg: "unknown", severety: 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
209extern "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(options: to);
219 // move memory
220 *to = *from;
221 // Reset pointers on source
222 sass_reset_options(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(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(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(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(nmemb: 1, size: 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(nmemb: 1, size: 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(nmemb: 1, size: 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(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(options: ctx, input_path);
357 } catch (...) {
358 handle_errors(c_ctx: 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(nmemb: 1, size: 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(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(c_ctx: 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(c_ctx: 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(c_ctx: 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(c_ctx: data_ctx) | 1; }
407 Context* cpp_ctx = new Data_Context(*data_ctx);
408 return sass_compile_context(c_ctx: 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(c_ctx: file_ctx) | 1; }
421 Context* cpp_ctx = new File_Context(*file_ctx);
422 return sass_compile_context(c_ctx: 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(c_ctx: 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(list: options->c_functions);
487 sass_delete_importer_list(list: options->c_importers);
488 sass_delete_importer_list(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(ptr: cur->string);
497 free(ptr: 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(ptr: cur->string);
509 free(ptr: cur);
510 cur = next;
511 }
512 }
513 // Free options strings
514 free(ptr: options->input_path);
515 free(ptr: options->output_path);
516 free(ptr: options->plugin_path);
517 free(ptr: options->include_path);
518 free(ptr: options->source_map_file);
519 free(ptr: 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(ptr: ctx->output_string);
541 if (ctx->source_map_string) free(ptr: ctx->source_map_string);
542 if (ctx->error_message) free(ptr: ctx->error_message);
543 if (ctx->error_text) free(ptr: ctx->error_text);
544 if (ctx->error_json) free(ptr: ctx->error_json);
545 if (ctx->error_file) free(ptr: ctx->error_file);
546 if (ctx->error_src) free(ptr: 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(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(ptr: compiler);
576 }
577
578 void ADDCALL sass_delete_options (struct Sass_Options* options)
579 {
580 sass_clear_options(options); free(ptr: 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(ptr: 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(ptr: ctx->source_string);
595 // clear the context and free it
596 sass_clear_context(ctx); free(ptr: 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(to: ctx, from: opt); }
608 void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* ctx, struct Sass_Options* opt) { copy_options(to: ctx, from: 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(nmemb: 1, size: sizeof(struct string_list));
676 if (include_path == 0) return;
677 include_path->string = path ? sass_copy_c_string(str: 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(nmemb: 1, size: sizeof(struct string_list));
728 if (plugin_path == 0) return;
729 plugin_path->string = path ? sass_copy_c_string(str: 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}
742

source code of gtk/subprojects/libsass/src/sass_context.cpp