From 071eebe797ed0e16f725357cc99144fd414520c8 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Mon, 8 Apr 2019 00:59:04 +0200 Subject: [PATCH 1/2] Implement `capture_stderr` C-API option As an embeddable library we should try to play nice with our parents resources. It is therefore desirable to have a way to capture messages on stderr. This makes it easier and safer to use libsass in eg. threaded environments. Core errors (mainly memory allocation problems) and dev/debug data is still printed to stderr directly. --- docs/api-context-internal.md | 7 +++++ docs/api-context.md | 11 +++++++ include/sass/context.h | 2 ++ src/bind.cpp | 6 ++-- src/bind.hpp | 2 +- src/context.cpp | 10 ++++++ src/context.hpp | 6 ++++ src/error_handling.cpp | 60 +++++++++++++++++++++--------------- src/error_handling.hpp | 15 +++++---- src/eval.cpp | 17 ++++++---- src/expand.cpp | 6 ++-- src/fn_strings.cpp | 2 +- src/parser.cpp | 3 +- src/sass_context.cpp | 23 +++++++++++++- src/sass_context.hpp | 7 +++++ 15 files changed, 130 insertions(+), 47 deletions(-) diff --git a/docs/api-context-internal.md b/docs/api-context-internal.md index 1a2818b345..a0ae47f6e5 100644 --- a/docs/api-context-internal.md +++ b/docs/api-context-internal.md @@ -51,6 +51,10 @@ struct Sass_Options : Sass_Output_Options { // Treat source_string as sass (as opposed to scss) bool is_indented_syntax_src; + // If this options is set, nothing will be printed to stderr anymore + // The aggregated output on stderr can be fetched via stderr_string + bool suppress_stderr; + // The input path is used for source map // generation. It can be used to define // something with string compilation or to @@ -105,6 +109,9 @@ struct Sass_Context : Sass_Options // generated output data char* output_string; + // messages on stderr + char* stderr_string; + // generated source map json char* source_map_string; diff --git a/docs/api-context.md b/docs/api-context.md index d51b807705..af5674357d 100644 --- a/docs/api-context.md +++ b/docs/api-context.md @@ -46,6 +46,11 @@ bool omit_source_map_url; bool is_indented_syntax_src; ``` ```C +// If this options is set, nothing will be printed to stderr anymore +// The aggregated output on stderr can be fetched via stderr_string +bool suppress_stderr; +``` +```C // The input path is used for source map // generating. It can be used to define // something with string compilation or to @@ -111,6 +116,10 @@ enum Sass_Input_Style type; char* output_string; ``` ```C +// messages on stderr +char* stderr_string; +``` +```C // generated source map json char* source_map_string; ``` @@ -197,6 +206,7 @@ void sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct S // Getters for Sass_Context values const char* sass_context_get_output_string (struct Sass_Context* ctx); +const char* sass_context_get_stderr_string (struct Sass_Context* ctx); int sass_context_get_error_status (struct Sass_Context* ctx); const char* sass_context_get_error_json (struct Sass_Context* ctx); const char* sass_context_get_error_text (struct Sass_Context* ctx); @@ -262,6 +272,7 @@ void sass_option_set_source_map_contents (struct Sass_Options* options, bool sou void sass_option_set_source_map_file_urls (struct Sass_Options* options, bool source_map_file_urls); void sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url); void sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src); +void sass_option_set_suppress_stderr (struct Sass_Options* options, bool suppress_stderr); void sass_option_set_indent (struct Sass_Options* options, const char* indent); void sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed); void sass_option_set_input_path (struct Sass_Options* options, const char* input_path); diff --git a/include/sass/context.h b/include/sass/context.h index 93c59d7206..d41886c439 100644 --- a/include/sass/context.h +++ b/include/sass/context.h @@ -96,6 +96,7 @@ ADDAPI void ADDCALL sass_option_set_source_map_contents (struct Sass_Options* op ADDAPI void ADDCALL sass_option_set_source_map_file_urls (struct Sass_Options* options, bool source_map_file_urls); ADDAPI void ADDCALL sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url); ADDAPI void ADDCALL sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src); +ADDAPI void ADDCALL sass_option_set_suppress_stderr (struct Sass_Options* options, bool suppress_stderr); ADDAPI void ADDCALL sass_option_set_indent (struct Sass_Options* options, const char* indent); ADDAPI void ADDCALL sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed); ADDAPI void ADDCALL sass_option_set_input_path (struct Sass_Options* options, const char* input_path); @@ -111,6 +112,7 @@ ADDAPI void ADDCALL sass_option_set_c_functions (struct Sass_Options* options, S // Getters for Sass_Context values ADDAPI const char* ADDCALL sass_context_get_output_string (struct Sass_Context* ctx); +ADDAPI const char* ADDCALL sass_context_get_stderr_string (struct Sass_Context* ctx); ADDAPI int ADDCALL sass_context_get_error_status (struct Sass_Context* ctx); ADDAPI const char* ADDCALL sass_context_get_error_json (struct Sass_Context* ctx); ADDAPI const char* ADDCALL sass_context_get_error_text (struct Sass_Context* ctx); diff --git a/src/bind.cpp b/src/bind.cpp index e9f6bbe440..abdcb0bb8d 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -11,7 +11,7 @@ namespace Sass { - void bind(std::string type, std::string name, Parameters_Obj ps, Arguments_Obj as, Env* env, Eval* eval, Backtraces& traces) + void bind(std::string type, std::string name, Parameters_Obj ps, Arguments_Obj as, Context* ctx, Env* env, Eval* eval, Backtraces& traces) { std::string callee(type + " " + name); @@ -194,7 +194,9 @@ namespace Sass { msg << (LP == 1 ? " argument" : " arguments"); msg << " but " << arg_count; msg << (arg_count == 1 ? " was passed" : " were passed."); - deprecated_bind(msg.str(), as->pstate()); + // ToDo: we only need ctx here to capture the message on stderr + // ToDo: once deprecation is gone, remove it from method args + ctx->print_stderr(deprecated_bind(msg.str(), as->pstate())); while (arglist->length() > LP - ip) { arglist->elements().erase(arglist->elements().end() - 1); diff --git a/src/bind.hpp b/src/bind.hpp index 57bcd01f97..b26ffd19a8 100644 --- a/src/bind.hpp +++ b/src/bind.hpp @@ -8,7 +8,7 @@ namespace Sass { - void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Env*, Eval*, Backtraces& traces); + void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Context* ctx, Env*, Eval*, Backtraces& traces); } diff --git a/src/context.cpp b/src/context.cpp index 088a70d3f9..c2412daa44 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -76,6 +76,8 @@ namespace Sass { head_imports(0), plugins(), emitter(c_options), + CERR(std::cerr), + STDERR(), ast_gc(), strings(), @@ -142,6 +144,14 @@ namespace Sass { sort (c_importers.begin(), c_importers.end(), sort_importers); } + void Context::print_stderr(const std::string& msg) + { + STDERR << msg; + if (!c_options.suppress_stderr) { + CERR << msg; + } + } + Context::~Context() { // resources were allocated by malloc diff --git a/src/context.hpp b/src/context.hpp index d18cd38177..7fc56b9b30 100644 --- a/src/context.hpp +++ b/src/context.hpp @@ -2,6 +2,7 @@ #define SASS_CONTEXT_H #include +#include #include #include @@ -44,6 +45,9 @@ namespace Sass { Plugins plugins; Output emitter; + std::ostream& CERR; + std::ostringstream STDERR; + // generic ast node garbage container // used to avoid possible circular refs CallStack ast_gc; @@ -104,6 +108,8 @@ namespace Sass { Sass_Output_Style output_style() { return c_options.output_style; }; std::vector get_included_files(bool skip = false, size_t headers = 0); + void print_stderr(const std::string& msg); + private: void collect_plugin_paths(const char* paths_str); void collect_plugin_paths(string_list* paths_array); diff --git a/src/error_handling.cpp b/src/error_handling.cpp index c0cf739eb7..6c002f0597 100644 --- a/src/error_handling.cpp +++ b/src/error_handling.cpp @@ -134,66 +134,78 @@ namespace Sass { } - - void warn(std::string msg, ParserState pstate) + std::string warn(std::string msg, ParserState pstate) { - std::cerr << "Warning: " << msg << std::endl; + std::ostringstream sstrm; + sstrm << "Warning: " << msg << std::endl; + return sstrm.str(); } - void warning(std::string msg, ParserState pstate) + std::string warning(std::string msg, ParserState pstate) { std::string cwd(Sass::File::get_cwd()); std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); std::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path)); - std::cerr << "WARNING on line " << pstate.line+1 << ", column " << pstate.column+1 << " of " << output_path << ":" << std::endl; - std::cerr << msg << std::endl << std::endl; + std::ostringstream sstrm; + sstrm << "WARNING on line " << pstate.line + 1; + sstrm << ", column " << pstate.column + 1; + sstrm << " of " << output_path << std::endl; + sstrm << msg << std::endl; + sstrm << std::endl; + return sstrm.str(); } - void warn(std::string msg, ParserState pstate, Backtrace* bt) + std::string warn(std::string msg, ParserState pstate, Backtrace* bt) { - warn(msg, pstate); + return warn(msg, pstate); } - void deprecated_function(std::string msg, ParserState pstate) + std::string deprecated_function(std::string msg, ParserState pstate) { std::string cwd(Sass::File::get_cwd()); std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); std::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path)); - std::cerr << "DEPRECATION WARNING: " << msg << std::endl; - std::cerr << "will be an error in future versions of Sass." << std::endl; - std::cerr << " on line " << pstate.line+1 << " of " << output_path << std::endl; + std::ostringstream sstrm; + sstrm << "DEPRECATION WARNING: " << msg << std::endl; + sstrm << "will be an error in future versions of Sass." << std::endl; + sstrm << " on line " << pstate.line+1 << " of " << output_path << std::endl; + return sstrm.str(); } - void deprecated(std::string msg, std::string msg2, bool with_column, ParserState pstate) + std::string deprecated(std::string msg, std::string msg2, bool with_column, ParserState pstate) { std::string cwd(Sass::File::get_cwd()); std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); std::string output_path(Sass::File::path_for_console(rel_path, pstate.path, pstate.path)); - std::cerr << "DEPRECATION WARNING on line " << pstate.line + 1; - if (with_column) std::cerr << ", column " << pstate.column + pstate.offset.column + 1; - if (output_path.length()) std::cerr << " of " << output_path; - std::cerr << ":" << std::endl; - std::cerr << msg << std::endl; - if (msg2.length()) std::cerr << msg2 << std::endl; - std::cerr << std::endl; + std::ostringstream sstrm; + sstrm << "DEPRECATION WARNING on line " << pstate.line + 1; + if (with_column) sstrm << ", column " << pstate.column + pstate.offset.column + 1; + if (output_path.length()) sstrm << " of " << output_path; + sstrm << ":" << std::endl; + sstrm << msg << std::endl; + if (msg2.length()) sstrm << msg2 << std::endl; + sstrm << std::endl; + return sstrm.str(); } - void deprecated_bind(std::string msg, ParserState pstate) + std::string deprecated_bind(std::string msg, ParserState pstate) { std::string cwd(Sass::File::get_cwd()); std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); std::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path)); - std::cerr << "WARNING: " << msg << std::endl; - std::cerr << " on line " << pstate.line+1 << " of " << output_path << std::endl; - std::cerr << "This will be an error in future versions of Sass." << std::endl; + std::ostringstream sstrm; + sstrm << "WARNING: " << msg << std::endl; + sstrm << " on line " << pstate.line+1 << " of " << output_path << std::endl; + sstrm << "This will be an error in future versions of Sass." << std::endl; + return sstrm.str(); } // should be replaced with error with backtraces diff --git a/src/error_handling.hpp b/src/error_handling.hpp index 24fedec4c0..c6d7d687d2 100644 --- a/src/error_handling.hpp +++ b/src/error_handling.hpp @@ -212,14 +212,13 @@ namespace Sass { } - void warn(std::string msg, ParserState pstate); - void warn(std::string msg, ParserState pstate, Backtrace* bt); - void warning(std::string msg, ParserState pstate); - - void deprecated_function(std::string msg, ParserState pstate); - void deprecated(std::string msg, std::string msg2, bool with_column, ParserState pstate); - void deprecated_bind(std::string msg, ParserState pstate); - // void deprecated(std::string msg, ParserState pstate, Backtrace* bt); + std::string warn(std::string msg, ParserState pstate); + std::string warn(std::string msg, ParserState pstate, Backtrace* bt); + std::string warning(std::string msg, ParserState pstate); + + std::string deprecated_function(std::string msg, ParserState pstate); + std::string deprecated(std::string msg, std::string msg2, bool with_column, ParserState pstate); + std::string deprecated_bind(std::string msg, ParserState pstate); void coreError(std::string msg, ParserState pstate); void error(std::string msg, ParserState pstate, Backtraces& traces); diff --git a/src/eval.cpp b/src/eval.cpp index 71bd0aea2d..a02ffe889b 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -389,9 +389,11 @@ namespace Sass { std::string result(unquote(message->to_sass())); std::cerr << "WARNING: " << result << std::endl; + std::ostringstream sstrm; traces.push_back(Backtrace(w->pstate())); - std::cerr << traces_to_string(traces, " "); - std::cerr << std::endl; + sstrm << traces_to_string(traces, " "); + sstrm << std::endl; + ctx.print_stderr(sstrm.str()); options().output_style = outstyle; traces.pop_back(); return 0; @@ -485,8 +487,11 @@ namespace Sass { std::string output_path(Sass::File::path_for_console(rel_path, abs_path, d->pstate().path)); options().output_style = outstyle; - std::cerr << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result; - std::cerr << std::endl; + std::ostringstream sstrm; + sstrm << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result; + sstrm << std::endl; + ctx.print_stderr(sstrm.str()); + return 0; } @@ -1048,7 +1053,7 @@ namespace Sass { env_stack().push_back(&fn_env); if (func || body) { - bind(std::string("Function"), c->name(), params, args, &fn_env, this, traces); + bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this, traces); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); callee_stack().push_back({ @@ -1088,7 +1093,7 @@ namespace Sass { // populates env with default values for params std::string ff(c->name()); - bind(std::string("Function"), c->name(), params, args, &fn_env, this, traces); + bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this, traces); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); callee_stack().push_back({ diff --git a/src/expand.cpp b/src/expand.cpp index 0a40410ed4..a5f72dc701 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -685,11 +685,11 @@ namespace Sass { d->name() == "expression" || d->name() == "url" )) { - deprecated( + ctx.print_stderr(deprecated( "Naming a function \"" + d->name() + "\" is disallowed and will be an error in future versions of Sass.", "This name conflicts with an existing CSS function with special parse rules.", false, d->pstate() - ); + )); } // set the static link so we can have lexical scoping @@ -746,7 +746,7 @@ namespace Sass { new_env.local_frame()["@content[m]"] = thunk; } - bind(std::string("Mixin"), c->name(), params, args, &new_env, &eval, traces); + bind(std::string("Mixin"), c->name(), params, args, &ctx, &new_env, &eval, traces); Block_Obj trace_block = SASS_MEMORY_NEW(Block, c->pstate()); Trace_Obj trace = SASS_MEMORY_NEW(Trace, c->pstate(), c->name(), trace_block); diff --git a/src/fn_strings.cpp b/src/fn_strings.cpp index 1b0ef38a82..6e8efdaf9d 100644 --- a/src/fn_strings.cpp +++ b/src/fn_strings.cpp @@ -56,7 +56,7 @@ namespace Sass { val = Cast(arg) ? "null" : val; ctx.c_options.output_style = oldstyle; - deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate); + ctx.print_stderr(deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate)); return ex; } throw std::runtime_error("Invalid Data Type for unquote"); diff --git a/src/parser.cpp b/src/parser.cpp index cfb389d48f..df3fea8787 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1679,7 +1679,8 @@ namespace Sass { if (lex< ampersand >()) { if (match< ampersand >()) { - warning("In Sass, \"&&\" means two copies of the parent selector. You probably want to use \"and\" instead.", pstate); + ctx.print_stderr(warning("In Sass, \"&&\" means two copies of the parent" + " selector. You probably want to use \"and\" instead.", pstate)); } return SASS_MEMORY_NEW(Parent_Reference, pstate); } diff --git a/src/sass_context.cpp b/src/sass_context.cpp index cca864f1cd..59c2f90d82 100644 --- a/src/sass_context.cpp +++ b/src/sass_context.cpp @@ -119,6 +119,7 @@ namespace Sass { c_ctx->error_column = e.pstate.column + 1; c_ctx->error_src = e.pstate.src; c_ctx->output_string = 0; + c_ctx->stderr_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } @@ -135,6 +136,7 @@ namespace Sass { c_ctx->error_text = sass_copy_c_string(ba.what()); c_ctx->error_status = 2; c_ctx->output_string = 0; + c_ctx->stderr_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } @@ -151,6 +153,7 @@ namespace Sass { c_ctx->error_text = sass_copy_c_string(e.what()); c_ctx->error_status = 3; c_ctx->output_string = 0; + c_ctx->stderr_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } @@ -167,6 +170,7 @@ namespace Sass { c_ctx->error_text = sass_copy_c_string(e.c_str()); c_ctx->error_status = 4; c_ctx->output_string = 0; + c_ctx->stderr_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } @@ -183,6 +187,7 @@ namespace Sass { c_ctx->error_text = sass_copy_c_string(e); c_ctx->error_status = 4; c_ctx->output_string = 0; + c_ctx->stderr_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } @@ -198,6 +203,7 @@ namespace Sass { c_ctx->error_text = sass_copy_c_string("unknown"); c_ctx->error_status = 5; c_ctx->output_string = 0; + c_ctx->stderr_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } @@ -504,9 +510,19 @@ extern "C" { // compile the parsed root block try { compiler->c_ctx->output_string = cpp_ctx->render(root); } // pass catched errors to generic error handler - catch (...) { return handle_errors(compiler->c_ctx) | 1; } + catch (...) { + // get aggregated messages on stderr as char* + std::string STDERR_STR = cpp_ctx->STDERR.str(); + char* STDERR = sass_copy_string(STDERR_STR.c_str()); + compiler->c_ctx->stderr_string = STDERR; + return handle_errors(compiler->c_ctx) | 1; + } // generate source map json and store on context compiler->c_ctx->source_map_string = cpp_ctx->render_srcmap(); + // get aggregated messages on stderr as char* + std::string STDERR_STR = cpp_ctx->STDERR.str(); + char* STDERR = sass_copy_string(STDERR_STR.c_str()); + compiler->c_ctx->stderr_string = STDERR; // success return 0; } @@ -589,6 +605,7 @@ extern "C" { if (ctx == 0) return; // release the allocated memory (mostly via sass_copy_c_string) if (ctx->output_string) free(ctx->output_string); + if (ctx->stderr_string) free(ctx->stderr_string); if (ctx->source_map_string) free(ctx->source_map_string); if (ctx->error_message) free(ctx->error_message); if (ctx->error_text) free(ctx->error_text); @@ -597,6 +614,7 @@ extern "C" { free_string_array(ctx->included_files); // play safe and reset properties ctx->output_string = 0; + ctx->stderr_string = 0; ctx->source_map_string = 0; ctx->error_message = 0; ctx->error_text = 0; @@ -682,6 +700,7 @@ extern "C" { IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_file_urls); IMPLEMENT_SASS_OPTION_ACCESSOR(bool, omit_source_map_url); IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src); + IMPLEMENT_SASS_OPTION_ACCESSOR(bool, suppress_stderr); IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Function_List, c_functions); IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_importers); IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_headers); @@ -704,6 +723,7 @@ extern "C" { IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_column); IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_src); IMPLEMENT_SASS_CONTEXT_GETTER(const char*, output_string); + IMPLEMENT_SASS_CONTEXT_GETTER(const char*, stderr_string); IMPLEMENT_SASS_CONTEXT_GETTER(const char*, source_map_string); IMPLEMENT_SASS_CONTEXT_GETTER(char**, included_files); @@ -713,6 +733,7 @@ extern "C" { IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_text); IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_file); IMPLEMENT_SASS_CONTEXT_TAKER(char*, output_string); + IMPLEMENT_SASS_CONTEXT_TAKER(char*, stderr_string); IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string); IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files); diff --git a/src/sass_context.hpp b/src/sass_context.hpp index 8ae1fb12cd..7b0097da0e 100644 --- a/src/sass_context.hpp +++ b/src/sass_context.hpp @@ -23,6 +23,10 @@ struct Sass_Options : Sass_Output_Options { // Treat source_string as sass (as opposed to scss) bool is_indented_syntax_src; + // If this options is set, nothing will be printed to stderr anymore + // The aggregated output on stderr can be fetched via stderr_string + bool suppress_stderr; + // The input path is used for source map // generation. It can be used to define // something with string compilation or to @@ -78,6 +82,9 @@ struct Sass_Context : Sass_Options // generated output data char* output_string; + // messages on stderr + char* stderr_string; + // generated source map json char* source_map_string; From 53405ece6b0714ad05ecdb31f7440be846c07359 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Mon, 8 Apr 2019 03:55:39 +0200 Subject: [PATCH 2/2] Move `capture_stderr` to inspect options --- src/bind.cpp | 2 +- src/context.cpp | 9 --------- src/context.hpp | 3 --- src/eval.cpp | 4 ++-- src/expand.cpp | 2 +- src/fn_strings.cpp | 2 +- src/operators.cpp | 14 +++++++------- src/parser.cpp | 2 +- src/sass.hpp | 24 ++++++++++++++++++++++-- src/sass_context.cpp | 4 ++-- src/sass_context.hpp | 4 ---- 11 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/bind.cpp b/src/bind.cpp index abdcb0bb8d..83c0e59655 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -196,7 +196,7 @@ namespace Sass { msg << (arg_count == 1 ? " was passed" : " were passed."); // ToDo: we only need ctx here to capture the message on stderr // ToDo: once deprecation is gone, remove it from method args - ctx->print_stderr(deprecated_bind(msg.str(), as->pstate())); + ctx->c_options.print_stderr(deprecated_bind(msg.str(), as->pstate())); while (arglist->length() > LP - ip) { arglist->elements().erase(arglist->elements().end() - 1); diff --git a/src/context.cpp b/src/context.cpp index c2412daa44..da02dc4b16 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -77,7 +77,6 @@ namespace Sass { plugins(), emitter(c_options), CERR(std::cerr), - STDERR(), ast_gc(), strings(), @@ -144,14 +143,6 @@ namespace Sass { sort (c_importers.begin(), c_importers.end(), sort_importers); } - void Context::print_stderr(const std::string& msg) - { - STDERR << msg; - if (!c_options.suppress_stderr) { - CERR << msg; - } - } - Context::~Context() { // resources were allocated by malloc diff --git a/src/context.hpp b/src/context.hpp index 7fc56b9b30..3e0d899563 100644 --- a/src/context.hpp +++ b/src/context.hpp @@ -46,7 +46,6 @@ namespace Sass { Output emitter; std::ostream& CERR; - std::ostringstream STDERR; // generic ast node garbage container // used to avoid possible circular refs @@ -108,8 +107,6 @@ namespace Sass { Sass_Output_Style output_style() { return c_options.output_style; }; std::vector get_included_files(bool skip = false, size_t headers = 0); - void print_stderr(const std::string& msg); - private: void collect_plugin_paths(const char* paths_str); void collect_plugin_paths(string_list* paths_array); diff --git a/src/eval.cpp b/src/eval.cpp index a02ffe889b..226db6368c 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -393,7 +393,7 @@ namespace Sass { traces.push_back(Backtrace(w->pstate())); sstrm << traces_to_string(traces, " "); sstrm << std::endl; - ctx.print_stderr(sstrm.str()); + ctx.c_options.print_stderr(sstrm.str()); options().output_style = outstyle; traces.pop_back(); return 0; @@ -490,7 +490,7 @@ namespace Sass { std::ostringstream sstrm; sstrm << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result; sstrm << std::endl; - ctx.print_stderr(sstrm.str()); + ctx.c_options.print_stderr(sstrm.str()); return 0; } diff --git a/src/expand.cpp b/src/expand.cpp index a5f72dc701..ad7cac7b83 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -685,7 +685,7 @@ namespace Sass { d->name() == "expression" || d->name() == "url" )) { - ctx.print_stderr(deprecated( + ctx.c_options.print_stderr(deprecated( "Naming a function \"" + d->name() + "\" is disallowed and will be an error in future versions of Sass.", "This name conflicts with an existing CSS function with special parse rules.", false, d->pstate() diff --git a/src/fn_strings.cpp b/src/fn_strings.cpp index 6e8efdaf9d..dd500dc2e3 100644 --- a/src/fn_strings.cpp +++ b/src/fn_strings.cpp @@ -56,7 +56,7 @@ namespace Sass { val = Cast(arg) ? "null" : val; ctx.c_options.output_style = oldstyle; - ctx.print_stderr(deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate)); + ctx.c_options.print_stderr(deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate)); return ex; } throw std::runtime_error("Invalid Data Type for unquote"); diff --git a/src/operators.cpp b/src/operators.cpp index bf312b8f35..533deda598 100644 --- a/src/operators.cpp +++ b/src/operators.cpp @@ -58,14 +58,14 @@ namespace Sass { bool gte(Expression_Obj lhs, Expression_Obj rhs) { return !cmp(lhs, rhs, Sass_OP::GTE) || eq(lhs, rhs); } /* colour math deprecation warning */ - void op_color_deprecation(enum Sass_OP op, std::string lsh, std::string rhs, const ParserState& pstate) + void op_color_deprecation(enum Sass_OP op, std::string lsh, std::string rhs, struct Sass_Inspect_Options opt, const ParserState& pstate) { - deprecated( + opt.print_stderr(deprecated( "The operation `" + lsh + " " + sass_op_to_name(op) + " " + rhs + "` is deprecated and will be an error in future versions.", "Consider using Sass's color functions instead.\n" "https://sass-lang.com/documentation/Sass/Script/Functions.html#other_color_functions", - /*with_column=*/false, pstate); + /*with_column=*/false, pstate)); } /* static function, throws OperationError, has no traces but optional pstate for returned value */ @@ -130,7 +130,7 @@ namespace Sass { throw Exception::ZeroDivisionError(lhs, rhs); } - op_color_deprecation(op, lhs.to_string(), rhs.to_string(), pstate); + op_color_deprecation(op, lhs.to_string(), rhs.to_string(), opt, pstate); return SASS_MEMORY_NEW(Color_RGBA, pstate, @@ -218,7 +218,7 @@ namespace Sass { switch (op) { case Sass_OP::ADD: case Sass_OP::MUL: { - op_color_deprecation(op, lhs.to_string(), rhs.to_string(opt), pstate); + op_color_deprecation(op, lhs.to_string(), rhs.to_string(opt), opt, pstate); return SASS_MEMORY_NEW(Color_RGBA, pstate, ops[op](lval, rhs.r()), @@ -229,7 +229,7 @@ namespace Sass { case Sass_OP::SUB: case Sass_OP::DIV: { std::string color(rhs.to_string(opt)); - op_color_deprecation(op, lhs.to_string(), color, pstate); + op_color_deprecation(op, lhs.to_string(), color, opt, pstate); return SASS_MEMORY_NEW(String_Quoted, pstate, lhs.to_string(opt) @@ -251,7 +251,7 @@ namespace Sass { throw Exception::ZeroDivisionError(lhs, rhs); } - op_color_deprecation(op, lhs.to_string(), rhs.to_string(), pstate); + op_color_deprecation(op, lhs.to_string(), rhs.to_string(), opt, pstate); return SASS_MEMORY_NEW(Color_RGBA, pstate, diff --git a/src/parser.cpp b/src/parser.cpp index df3fea8787..6af7eb7949 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1679,7 +1679,7 @@ namespace Sass { if (lex< ampersand >()) { if (match< ampersand >()) { - ctx.print_stderr(warning("In Sass, \"&&\" means two copies of the parent" + ctx.c_options.print_stderr(warning("In Sass, \"&&\" means two copies of the parent" " selector. You probably want to use \"and\" instead.", pstate)); } return SASS_MEMORY_NEW(Parent_Reference, pstate); } diff --git a/src/sass.hpp b/src/sass.hpp index 014e4fa1a9..17703bca42 100644 --- a/src/sass.hpp +++ b/src/sass.hpp @@ -53,6 +53,8 @@ // For C++ helper #include +#include +#include // output behaviours namespace Sass { @@ -96,12 +98,30 @@ struct Sass_Inspect_Options { // Precision for fractional numbers int precision; + // If this options is set, nothing will be printed to stderr anymore + // The aggregated output on stderr can be fetched via stderr_string + bool suppress_stderr; + + // messages on stderr + std::string stderr_str; + // initialization list (constructor with defaults) Sass_Inspect_Options(Sass_Output_Style style = Sass::NESTED, - int precision = 10) - : output_style(style), precision(precision) + int precision = 10, + bool suppress_stderr = false, + std::string stderr_str = "") + : output_style(style), precision(precision), + suppress_stderr(suppress_stderr), + stderr_str(stderr_str) { } + void print_stderr(const std::string& msg) { + stderr_str += msg; + if (!suppress_stderr) { + std::cerr << msg; + } + } + }; // sass config options structure diff --git a/src/sass_context.cpp b/src/sass_context.cpp index 59c2f90d82..dde81ad0fe 100644 --- a/src/sass_context.cpp +++ b/src/sass_context.cpp @@ -512,7 +512,7 @@ extern "C" { // pass catched errors to generic error handler catch (...) { // get aggregated messages on stderr as char* - std::string STDERR_STR = cpp_ctx->STDERR.str(); + std::string STDERR_STR = cpp_ctx->c_options.stderr_str; char* STDERR = sass_copy_string(STDERR_STR.c_str()); compiler->c_ctx->stderr_string = STDERR; return handle_errors(compiler->c_ctx) | 1; @@ -520,7 +520,7 @@ extern "C" { // generate source map json and store on context compiler->c_ctx->source_map_string = cpp_ctx->render_srcmap(); // get aggregated messages on stderr as char* - std::string STDERR_STR = cpp_ctx->STDERR.str(); + std::string STDERR_STR = cpp_ctx->c_options.stderr_str; char* STDERR = sass_copy_string(STDERR_STR.c_str()); compiler->c_ctx->stderr_string = STDERR; // success diff --git a/src/sass_context.hpp b/src/sass_context.hpp index 7b0097da0e..271812615d 100644 --- a/src/sass_context.hpp +++ b/src/sass_context.hpp @@ -23,10 +23,6 @@ struct Sass_Options : Sass_Output_Options { // Treat source_string as sass (as opposed to scss) bool is_indented_syntax_src; - // If this options is set, nothing will be printed to stderr anymore - // The aggregated output on stderr can be fetched via stderr_string - bool suppress_stderr; - // The input path is used for source map // generation. It can be used to define // something with string compilation or to