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) json_mkstream(const sass::ostream & stream)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 handle_string_error(Sass_Context * c_ctx,const sass::string & msg,int severety)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 handle_error(Sass_Context * c_ctx)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 handle_errors(Sass_Context * c_ctx)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 sass_parse_block(Sass_Compiler * compiler)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); copy_options(struct Sass_Options * to,struct Sass_Options * from)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) sass_prepare_context(Sass_Context * c_ctx,Context * cpp_ctx)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) sass_compile_context(Sass_Context * c_ctx,Context * cpp_ctx)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 init_options(struct Sass_Options * options)329 inline void init_options (struct Sass_Options* options) 330 { 331 options->precision = 10; 332 options->indent = " "; 333 options->linefeed = LFEED; 334 } 335 sass_make_options(void)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 sass_make_file_context(const char * input_path)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 sass_make_data_context(char * source_string)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 sass_make_data_compiler(struct Sass_Data_Context * data_ctx)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 sass_make_file_compiler(struct Sass_File_Context * file_ctx)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 sass_compile_data_context(Sass_Data_Context * data_ctx)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 sass_compile_file_context(Sass_File_Context * file_ctx)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 sass_compiler_parse(struct Sass_Compiler * compiler)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 sass_compiler_execute(struct Sass_Compiler * compiler)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 sass_reset_options(struct Sass_Options * options)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 sass_clear_options(struct Sass_Options * options)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 sass_clear_context(struct Sass_Context * ctx)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 sass_delete_compiler(struct Sass_Compiler * compiler)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 sass_delete_options(struct Sass_Options * options)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 sass_delete_file_context(struct Sass_File_Context * ctx)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 sass_delete_data_context(struct Sass_Data_Context * ctx)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 sass_file_context_get_context(struct Sass_File_Context * ctx)600 struct Sass_Context* ADDCALL sass_file_context_get_context(struct Sass_File_Context* ctx) { return ctx; } sass_data_context_get_context(struct Sass_Data_Context * 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 sass_context_get_options(struct Sass_Context * ctx)604 struct Sass_Options* ADDCALL sass_context_get_options(struct Sass_Context* ctx) { return ctx; } sass_file_context_get_options(struct Sass_File_Context * ctx)605 struct Sass_Options* ADDCALL sass_file_context_get_options(struct Sass_File_Context* ctx) { return ctx; } sass_data_context_get_options(struct Sass_Data_Context * ctx)606 struct Sass_Options* ADDCALL sass_data_context_get_options(struct Sass_Data_Context* ctx) { return ctx; } sass_file_context_set_options(struct Sass_File_Context * ctx,struct Sass_Options * opt)607 void ADDCALL sass_file_context_set_options (struct Sass_File_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); } sass_data_context_set_options(struct Sass_Data_Context * ctx,struct Sass_Options * 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) sass_compiler_get_state(struct Sass_Compiler * compiler)611 enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler) { return compiler->state; } sass_compiler_get_context(struct Sass_Compiler * compiler)612 struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler) { return compiler->c_ctx; } sass_compiler_get_options(struct Sass_Compiler * compiler)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) sass_compiler_get_import_stack_size(struct Sass_Compiler * compiler)615 size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.size(); } sass_compiler_get_last_import(struct Sass_Compiler * compiler)616 Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.back(); } sass_compiler_get_import_entry(struct Sass_Compiler * compiler,size_t idx)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) sass_compiler_get_callee_stack_size(struct Sass_Compiler * compiler)619 size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->callee_stack.size(); } sass_compiler_get_last_callee(struct Sass_Compiler * compiler)620 Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler) { return &compiler->cpp_ctx->callee_stack.back(); } sass_compiler_get_callee_entry(struct Sass_Compiler * compiler,size_t idx)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 sass_context_get_included_files_size(struct Sass_Context * ctx)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) sass_option_push_include_path(struct Sass_Options * options,const char * path)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) sass_option_get_include_path_size(struct Sass_Options * options)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) sass_option_get_include_path(struct Sass_Options * options,size_t i)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) sass_option_get_plugin_path_size(struct Sass_Options * options)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) sass_option_get_plugin_path(struct Sass_Options * options,size_t i)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) sass_option_push_plugin_path(struct Sass_Options * options,const char * path)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 } 742