Commit 7ec14dff by xzyfer Committed by Michael Mifsud

Bump LibSass@3.5.3

parent eb5ad0a7
{ {
"name": "node-sass", "name": "node-sass",
"version": "4.9.0", "version": "4.9.0",
"libsass": "3.5.2", "libsass": "3.5.3",
"description": "Wrapper around libsass", "description": "Wrapper around libsass",
"license": "MIT", "license": "MIT",
"bugs": "https://github.com/sass/node-sass/issues", "bugs": "https://github.com/sass/node-sass/issues",
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
"object-merge": "^2.5.1", "object-merge": "^2.5.1",
"read-yaml": "^1.0.0", "read-yaml": "^1.0.0",
"rimraf": "^2.5.2", "rimraf": "^2.5.2",
"sass-spec": "^3.5.1", "sass-spec": "3.5.3",
"unique-temp-dir": "^1.0.0" "unique-temp-dir": "^1.0.0"
} }
} }
...@@ -25,63 +25,49 @@ else ...@@ -25,63 +25,49 @@ else
AM_CXXFLAGS += -std=c++0x AM_CXXFLAGS += -std=c++0x
endif endif
TEST_EXTENSIONS = .rb
if ENABLE_TESTS if ENABLE_TESTS
noinst_PROGRAMS = tester SASS_SASSC_PATH ?= $(top_srcdir)/sassc
SASS_SPEC_PATH ?= $(top_srcdir)/sass-spec
noinst_PROGRAMS = tester
tester_LDADD = src/libsass.la tester_LDADD = src/libsass.la
tester_SOURCES = $(SASS_SASSC_PATH)/sassc.c
tester_VERSION ?= `cd "$(SASS_SASSC_PATH)" && ./version.sh`
tester_CFLAGS = $(AM_CFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
tester_CXXFLAGS = $(AM_CXXFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
tester_LDFLAGS = $(AM_LDFLAGS) tester_LDFLAGS = $(AM_LDFLAGS)
nodist_tester_SOURCES = $(SASS_SASSC_PATH)/sassc.c
SASS_SASSC_VERSION ?= `cd "$(SASS_SASSC_PATH)" && ./version.sh`
tester_CFLAGS = $(AM_CFLAGS) -DSASSC_VERSION="\"$(SASS_SASSC_VERSION)\""
tester_CXXFLAGS = $(AM_CXXFLAGS) -DSASSC_VERSION="\"$(SASS_SASSC_VERSION)\""
if ENABLE_COVERAGE if ENABLE_COVERAGE
nodist_EXTRA_tester_SOURCES = non-existent-file-to-force-CXX-linking.cxx nodist_EXTRA_tester_SOURCES = non-existent-file-to-force-CXX-linking.cxx
endif endif
SASS_SASSC_PATH ?= $(top_srcdir)/sassc TESTS = $(SASS_SPEC_PATH)/sass-spec.rb
SASS_SPEC_PATH ?= $(top_srcdir)/sass-spec RB_LOG_COMPILER = ./script/tap-runner
AM_RB_LOG_FLAGS = $(RUBY)
TESTS = \
$(SASS_SPEC_PATH)/spec/basic \
$(SASS_SPEC_PATH)/spec/css \
$(SASS_SPEC_PATH)/spec/extend-tests \
$(SASS_SPEC_PATH)/spec/extends \
$(SASS_SPEC_PATH)/spec/libsass \
$(SASS_SPEC_PATH)/spec/libsass-closed-issues \
$(SASS_SPEC_PATH)/spec/maps \
$(SASS_SPEC_PATH)/spec/misc \
$(SASS_SPEC_PATH)/spec/regressions \
$(SASS_SPEC_PATH)/spec/scss \
$(SASS_SPEC_PATH)/spec/scss-tests \
$(SASS_SPEC_PATH)/spec/types
SASS_TEST_FLAGS = -V 3.5 --impl libsass SASS_TEST_FLAGS = -V 3.5 --impl libsass
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) ./script/tap-driver SASS_TEST_FLAGS += -r $(SASS_SPEC_PATH)
AM_LOG_FLAGS = -c ./tester $(LOG_FLAGS) SASS_TEST_FLAGS += -c $(top_srcdir)/tester$(EXEEXT)
if USE_TAP AM_TESTS_ENVIRONMENT = TEST_FLAGS='$(SASS_TEST_FLAGS)'
AM_LOG_FLAGS += -t
SASS_TEST_FLAGS += -t | tapout
LOG_COMPILER = ./script/tap-runner $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
else
LOG_COMPILER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
endif
SASS_TESTER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb SASS_TESTER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
SASS_TESTER += -c $(top_srcdir)/tester$(EXEEXT)
test: test:
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS) $(SASS_TESTER) $(SASS_TEST_FLAGS)
test_build: test_build:
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS) $(SASS_TESTER) $(SASS_TEST_FLAGS)
test_full: test_full:
$(SASS_TESTER) --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS) $(SASS_TESTER) --run-todo $(SASS_TEST_FLAGS)
test_probe: test_probe:
$(SASS_TESTER) --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS) $(SASS_TESTER) --probe-todo $(SASS_TEST_FLAGS)
.PHONY: test test_build test_full test_probe
endif endif
......
...@@ -9,6 +9,7 @@ AC_CONFIG_MACRO_DIR([m4]) ...@@ -9,6 +9,7 @@ AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_HEADERS([src/config.h])
AC_CONFIG_FILES([include/sass/version.h]) AC_CONFIG_FILES([include/sass/version.h])
AC_CONFIG_AUX_DIR([script]) AC_CONFIG_AUX_DIR([script])
# These are flags passed to automake # These are flags passed to automake
# Though they look like gcc flags! # Though they look like gcc flags!
AM_INIT_AUTOMAKE([foreign parallel-tests -Wall]) AM_INIT_AUTOMAKE([foreign parallel-tests -Wall])
...@@ -93,21 +94,16 @@ the --with-sass-spec-dir=<dir> argument. ...@@ -93,21 +94,16 @@ the --with-sass-spec-dir=<dir> argument.
;; ;;
esac esac
AC_SUBST(SASS_SPEC_PATH) AC_SUBST(SASS_SPEC_PATH)
else
# TODO: Remove this when automake requirements are 1.12+ # we do not really need these paths for non test build
AC_MSG_CHECKING([whether we can use TAP mode]) # but automake may error if we do not define them here
tmp=`$AWK '/TEST_LOG_DRIVER/' $srcdir/GNUmakefile.in` SASS_SPEC_PATH=sass-spec
if test "x$tmp" != "x"; then SASS_SASSC_PATH=sassc
use_tap=yes AC_SUBST(SASS_SPEC_PATH)
else AC_SUBST(SASS_SASSC_PATH)
use_tap=no
fi
AC_MSG_RESULT([$use_tap])
fi fi
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes") AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes")
AM_CONDITIONAL(USE_TAP, test "x$use_tap" = "xyes")
AC_ARG_ENABLE([coverage], AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage], [AS_HELP_STRING([--enable-coverage],
......
...@@ -14,6 +14,17 @@ There are several implementations of `libsass` for a variety of languages. Here ...@@ -14,6 +14,17 @@ There are several implementations of `libsass` for a variety of languages. Here
* [go_sass](https://github.com/suapapa/go_sass) * [go_sass](https://github.com/suapapa/go_sass)
* [go-sass](https://github.com/SamWhited/go-sass) * [go-sass](https://github.com/SamWhited/go-sass)
### Haskell
* [hLibsass](https://github.com/jakubfijalkowski/hlibsass)
* [hSass](https://github.com/jakubfijalkowski/hsass)
### Java
* [libsass-maven-plugin](https://github.com/warmuuh/libsass-maven-plugin)
* [jsass](https://github.com/bit3/jsass)
### JavaScript
* [sass.js](https://github.com/medialize/sass.js)
### Lua ### Lua
* [lua-sass](https://github.com/craigbarnes/lua-sass) * [lua-sass](https://github.com/craigbarnes/lua-sass)
...@@ -21,16 +32,14 @@ There are several implementations of `libsass` for a variety of languages. Here ...@@ -21,16 +32,14 @@ There are several implementations of `libsass` for a variety of languages. Here
* [libsass-net](https://github.com/darrenkopp/libsass-net) * [libsass-net](https://github.com/darrenkopp/libsass-net)
* [NSass](https://github.com/TBAPI-0KA/NSass) * [NSass](https://github.com/TBAPI-0KA/NSass)
* [Sass.Net](https://github.com/andyalm/Sass.Net) * [Sass.Net](https://github.com/andyalm/Sass.Net)
* [SharpScss](https://github.com/xoofx/SharpScss)
* [LibSassHost](https://github.com/Taritsyn/LibSassHost)
### node.js ### Nim
* [node-sass](https://github.com/andrew/node-sass) * [nim-sass](https://github.com/zacharycarter/nim-sass)
### Java
* [libsass-maven-plugin](https://github.com/warmuuh/libsass-maven-plugin)
* [jsass](https://github.com/bit3/jsass)
### JavaScript ### node.js
* [sass.js](https://github.com/medialize/sass.js) * [node-sass](https://github.com/sass/node-sass)
### Perl ### Perl
* [CSS::Sass](https://github.com/caldwell/CSS-Sass) * [CSS::Sass](https://github.com/caldwell/CSS-Sass)
......
LibSass currently expects all input to be utf8 encoded (and outputs only utf8), if you actually have any unicode characters at all. We do not support conversion between encodings, even if you declare it with a `@charset` rule. The text below was originally posted as an [issue](https://github.com/sass/libsass/issues/381) on the LibSass tracker. LibSass currently expects all input to be utf8 encoded (and outputs only utf8), if you actually have any unicode characters at all. We do not support conversion between encodings, even if you declare it with a `@charset` rule. The text below was originally posted as an [issue](https://github.com/sass/libsass/issues/381) on the LibSass tracker. Since then the status is outdated as LibSass now expects your
input to be utf8/ascii compatible, as it has been proven that reading ANSI (e.g. single byte encodings) as utf8 can lead to unexpected
behavior, which can in the worst case lead to buffer overruns/segfaults. Therefore LibSass now checks your input to be valid utf8 encoded!
### [Declaring character encodings in CSS](http://www.w3.org/International/questions/qa-css-charset.en) ### [Declaring character encodings in CSS](http://www.w3.org/International/questions/qa-css-charset.en)
This [explains](http://www.w3.org/International/questions/qa-css-charset.en) how the character encoding of a css file is determined. Since we are only dealing with local files, we never have a HTTP header. So the precedence should be 'charset' rule, byte-order mark (BOM) or auto-detection (finally falling back to system default/UTF-8). This may not sound too hard to implement, but what about import rules? The CSS specs do not forbid the mixing of different encodings! I solved that by converting all files to UTF-8 internally. On writing there is an option to tell the tool what encoding it should be (UTF-8 by default). One can also define if it should write a BOM or not and if it should add the charset declaration. This [explains](http://www.w3.org/International/questions/qa-css-charset.en) how the character encoding of a css file is determined. Since we are only dealing with local files, we never have a HTTP header. So the precedence should be 'charset' rule, byte-order mark (BOM) or auto-detection (finally falling back to system default/UTF-8). This may not sound too hard to implement, but what about import rules? The CSS specs do not forbid the mixing of different encodings! I [solved that](https://github.com/mgreter/webmerge/) by converting all files to UTF-8 internally. On writing there is an option to tell the tool what encoding it should be (UTF-8 by default). One can also define if it should write a BOM or not and if it should add the charset declaration.
Since my tool is written in perl, I have a lot of utilities at hand to deal with different unicode charsets. I'm pretty sure that most OSS uses [libiconv](https://www.gnu.org/software/libiconv/) to convert between different encodings. But I have now idea how easy/hard this would be to integrate platform independent (it seems doable). Since my [tool]((https://github.com/mgreter/webmerge/)) is written in perl, I have a lot of utilities at hand to deal with different unicode charsets. I'm pretty sure that most OSS uses [ICU](http://site.icu-project.org/) or [libiconv](https://www.gnu.org/software/libiconv/) to convert between different encodings. But I have now idea how easy/hard this would be to integrate platform independent (it seems doable). ANSII (single byte encoding) to utf8 is basically just a conversion table (for every supported code-page).
### Current status on LibSass unicode support ### Current status on LibSass unicode support
Currently LibSass seems to handle the common UTF-8 case pretty well. I believe it should correctly support all ASCII compatible encodings (like UTF-8 or Latin-1). If all includes use the same encoding, the output should be correct (in the same encoding). It should also handle unicode chars in [selectors, variable names and other identifiers](https://github.com/hcatlin/libsass/issues/244#issuecomment-34681227). This is true for all ASCII compatible encodings. So the main incompatible encodings (I'm aware of) are UTF-16/UTF-32 (which could be converted to UTF-8 with libiconv). LibSass should/is fully UTF (and therefore plain ASCII) compatible.
~~Currently LibSass seems to handle the common UTF-8 case pretty well. I believe it should correctly support all ASCII compatible encodings (like UTF-8 or Latin-1). If all includes use the same encoding, the output should be correct (in the same encoding). It should also handle unicode chars in [selectors, variable names and other identifiers](https://github.com/hcatlin/libsass/issues/244#issuecomment-34681227). This is true for all ASCII compatible encodings. So the main incompatible encodings (I'm aware of) are UTF-16/UTF-32 (which could be converted to UTF-8 with libiconv).~~
LibSass 3.5 will enforce that your input is either plain ASCII (chars below 127) or utf8. It does not handle anything else, but therefore ensures that the output is in a valid form. Before version 3.5 you were able to mix different code-pages, which yielded unexpected behavior.
### Current encoding auto detection ### Current encoding auto detection
LibSass currently reads all kind of BOMs and will error out if it finds something it doesn't know how to handle! It seems that it throws away the optional UTF-8 BOM (if any is found). IMO it would be nice if users could configure that (also if a charset rule should be added to the output). LibSass currently reads all kind of BOMs and will error out if it finds something it doesn't know how to handle! It seems that it throws away the optional UTF-8 BOM (if any is found). IMO it would be nice if users could configure that (also if a charset rule should be added to the output). But it does not really take any `@charset` into account, it always assumes your input is utf8 and ignores any given `@charset`!
### What is currently not supported ### What is currently not supported
- Using non ASCII compatible encodings (like UTF-16) - Using non ASCII compatible encodings (like UTF-16, Latin-1 etc.)
- Using non ASCII characters in different encodings in different includes - Using non ASCII characters in different encodings in different includes
### What is missing to support the above cases ### What is missing to support the above cases
- A way to convert between encodings (like libiconv) - A way to convert between encodings (like libiconv/ICU)
- Sniffing the charset inside the file (source is available) - Sniffing the charset inside the file (source is available)
- Handling the conversion on import (and export) - Handling the conversion on import (and export)
- Optional: Make output encoding configurable - Optional: Make output encoding configurable
...@@ -31,9 +37,9 @@ LibSass currently reads all kind of BOMs and will error out if it finds somethin ...@@ -31,9 +37,9 @@ LibSass currently reads all kind of BOMs and will error out if it finds somethin
I guess the current implementation should handle more than 99% of all real world use cases. I guess the current implementation should handle more than 99% of all real world use cases.
A) Unicode characters are still seldomly seen (as they can be written escaped) A) Unicode characters are still seldomly seen (as they can be written escaped)
B) It will still work if it's UTF-8 or in any of the most common known western ISO codepages. ~~B) It will still work if it's UTF-8 or in any of the most common known western ISO codepages.
Although I'm not sure how this applies to asian and other "exotic" codepages! Although I'm not sure how this applies to asian and other "exotic" codepages!~~
I guess the biggest Problem is to have libiconv (or some other) library as a dependency. Since it contains a lot of rules for the conversions, I see it as the only way to handle this correctly. Once that is sorted out it should be pretty much straight forward to implement the missing pieces (in parser.cpp - Parser::parse should return encoding and add Parser::sniff_charset, then convert the source byte stream to UTF-8). I guess the biggest Problem is to have libiconv/ICU (or some other) library as a dependency. Since it contains a lot of rules for the conversions, I see it as the only way to handle this correctly. Once that is sorted out it should be pretty much straight forward to implement the missing pieces (in parser.cpp - Parser::parse should return encoding and add Parser::sniff_charset, then convert the source byte stream to UTF-8).
I hope the statements above all hold true. Unicode is really not the easiest topic to wrap your head around. But since I did all the above recently in Perl, I wanted to document it here. Feel free to extend or criticize. I hope the statements above all hold true. Unicode is really not the easiest topic to wrap your head around. But since I did all the above recently in Perl, I wanted to document it here. Feel free to extend or criticize.
...@@ -149,6 +149,9 @@ ADDAPI size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* ...@@ -149,6 +149,9 @@ ADDAPI size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler*
ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler); ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler);
ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx); ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx);
// Push function for import extenions
ADDAPI void ADDCALL sass_option_push_import_extension (struct Sass_Options* options, const char* ext);
// Push function for paths (no manipulation support for now) // Push function for paths (no manipulation support for now)
ADDAPI void ADDCALL sass_option_push_plugin_path (struct Sass_Options* options, const char* path); ADDAPI void ADDCALL sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
ADDAPI void ADDCALL sass_option_push_include_path (struct Sass_Options* options, const char* path); ADDAPI void ADDCALL sass_option_push_include_path (struct Sass_Options* options, const char* path);
......
$@ | tapout tap $@ $TEST_FLAGS --tap --silent | tapout tap
\ No newline at end of file
...@@ -96,6 +96,8 @@ namespace Sass { ...@@ -96,6 +96,8 @@ namespace Sass {
// include_paths.push_back(CWD); // include_paths.push_back(CWD);
// collect more paths from different options // collect more paths from different options
collect_extensions(c_options.extension);
collect_extensions(c_options.extensions);
collect_include_paths(c_options.include_path); collect_include_paths(c_options.include_path);
collect_include_paths(c_options.include_paths); collect_include_paths(c_options.include_paths);
collect_plugin_paths(c_options.plugin_path); collect_plugin_paths(c_options.plugin_path);
...@@ -166,6 +168,37 @@ namespace Sass { ...@@ -166,6 +168,37 @@ namespace Sass {
{ {
} }
void Context::collect_extensions(const char* exts_str)
{
if (exts_str) {
const char* beg = exts_str;
const char* end = Prelexer::find_first<PATH_SEP>(beg);
while (end) {
std::string ext(beg, end - beg);
if (!ext.empty()) {
extensions.push_back(ext);
}
beg = end + 1;
end = Prelexer::find_first<PATH_SEP>(beg);
}
std::string ext(beg);
if (!ext.empty()) {
extensions.push_back(ext);
}
}
}
void Context::collect_extensions(string_list* paths_array)
{
while (paths_array)
{
collect_extensions(paths_array->string);
paths_array = paths_array->next;
}
}
void Context::collect_include_paths(const char* paths_str) void Context::collect_include_paths(const char* paths_str)
{ {
if (paths_str) { if (paths_str) {
...@@ -236,15 +269,20 @@ namespace Sass { ...@@ -236,15 +269,20 @@ namespace Sass {
// looks for alternatives and returns a list from one directory // looks for alternatives and returns a list from one directory
std::vector<Include> Context::find_includes(const Importer& import) std::vector<Include> Context::find_includes(const Importer& import)
{ {
// include configured extensions
std::vector<std::string> exts(File::defaultExtensions);
if (extensions.size() > 0) {
exts.insert(exts.end(), extensions.begin(), extensions.end());
}
// make sure we resolve against an absolute path // make sure we resolve against an absolute path
std::string base_path(rel2abs(import.base_path)); std::string base_path(rel2abs(import.base_path));
// first try to resolve the load path relative to the base path // first try to resolve the load path relative to the base path
std::vector<Include> vec(resolve_includes(base_path, import.imp_path)); std::vector<Include> vec(resolve_includes(base_path, import.imp_path, exts));
// then search in every include path (but only if nothing found yet) // then search in every include path (but only if nothing found yet)
for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i) for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i)
{ {
// call resolve_includes and individual base path and append all results // call resolve_includes and individual base path and append all results
std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path)); std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path, exts));
if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end()); if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end());
} }
// return vector // return vector
...@@ -365,6 +403,14 @@ namespace Sass { ...@@ -365,6 +403,14 @@ namespace Sass {
// process the resolved entry // process the resolved entry
else if (resolved.size() == 1) { else if (resolved.size() == 1) {
bool use_cache = c_importers.size() == 0; bool use_cache = c_importers.size() == 0;
if (resolved[0].deprecated) {
// emit deprecation warning when import resolves to a .css file
deprecated(
"Including .css files with @import is non-standard behaviour which will be removed in future versions of LibSass.",
"Use a custom importer to maintain this behaviour. Check your implementations documentation on how to create a custom importer.",
true, pstate
);
}
// use cache for the resource loading // use cache for the resource loading
if (use_cache && sheets.count(resolved[0].abs_path)) return resolved[0]; if (use_cache && sheets.count(resolved[0].abs_path)) return resolved[0];
// try to read the content of the resolved file entry // try to read the content of the resolved file entry
......
...@@ -67,6 +67,7 @@ namespace Sass { ...@@ -67,6 +67,7 @@ namespace Sass {
std::vector<std::string> plugin_paths; // relative paths to load plugins std::vector<std::string> plugin_paths; // relative paths to load plugins
std::vector<std::string> include_paths; // lookup paths for includes std::vector<std::string> include_paths; // lookup paths for includes
std::vector<std::string> extensions; // lookup extensions for imports`
...@@ -109,6 +110,8 @@ namespace Sass { ...@@ -109,6 +110,8 @@ namespace Sass {
void collect_plugin_paths(string_list* paths_array); void collect_plugin_paths(string_list* paths_array);
void collect_include_paths(const char* paths_str); void collect_include_paths(const char* paths_str);
void collect_include_paths(string_list* paths_array); void collect_include_paths(string_list* paths_array);
void collect_extensions(const char* extensions_str);
void collect_extensions(string_list* extensions_array);
std::string format_embedded_source_map(); std::string format_embedded_source_map();
std::string format_source_mapping_url(const std::string& out_path); std::string format_source_mapping_url(const std::string& out_path);
......
...@@ -559,7 +559,7 @@ namespace Sass { ...@@ -559,7 +559,7 @@ namespace Sass {
std::string m1 = std::string(mq1->is_restricted() ? "only" : mq1->is_negated() ? "not" : ""); std::string m1 = std::string(mq1->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
std::string t1 = mq1->media_type() ? mq1->media_type()->to_string(ctx.c_options) : ""; std::string t1 = mq1->media_type() ? mq1->media_type()->to_string(ctx.c_options) : "";
std::string m2 = std::string(mq2->is_restricted() ? "only" : mq1->is_negated() ? "not" : ""); std::string m2 = std::string(mq2->is_restricted() ? "only" : mq2->is_negated() ? "not" : "");
std::string t2 = mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : ""; std::string t2 = mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : "";
......
...@@ -627,6 +627,7 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) ...@@ -627,6 +627,7 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env)
Number_Ptr expression = Cast<Number>(node); Number_Ptr expression = Cast<Number>(node);
std::cerr << ind << "Number " << expression; std::cerr << ind << "Number " << expression;
std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " (" << pstate_source_position(node) << ")";
std::cerr << " [delayed: " << expression->is_delayed() << "] ";
std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
std::cerr << " [" << expression->value() << expression->unit() << "]" << std::cerr << " [" << expression->value() << expression->unit() << "]" <<
" [hash: " << expression->hash() << "] " << " [hash: " << expression->hash() << "] " <<
......
...@@ -599,10 +599,6 @@ namespace Sass { ...@@ -599,10 +599,6 @@ namespace Sass {
switch (op_type) { switch (op_type) {
case Sass_OP::EQ: return *l_n == *r_c ? bool_true : bool_false; case Sass_OP::EQ: return *l_n == *r_c ? bool_true : bool_false;
case Sass_OP::NEQ: return *l_n == *r_c ? bool_false : bool_true; case Sass_OP::NEQ: return *l_n == *r_c ? bool_false : bool_true;
case Sass_OP::LT: return *l_n < *r_c ? bool_true : bool_false;
case Sass_OP::GTE: return *l_n < *r_c ? bool_false : bool_true;
case Sass_OP::LTE: return *l_n < *r_c || *l_n == *r_c ? bool_true : bool_false;
case Sass_OP::GT: return *l_n < *r_c || *l_n == *r_c ? bool_false : bool_true;
case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
return Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, b_in->pstate()); return Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, b_in->pstate());
default: break; default: break;
...@@ -643,10 +639,6 @@ namespace Sass { ...@@ -643,10 +639,6 @@ namespace Sass {
switch (op_type) { switch (op_type) {
case Sass_OP::EQ: return *l_c == *r_n ? bool_true : bool_false; case Sass_OP::EQ: return *l_c == *r_n ? bool_true : bool_false;
case Sass_OP::NEQ: return *l_c == *r_n ? bool_false : bool_true; case Sass_OP::NEQ: return *l_c == *r_n ? bool_false : bool_true;
case Sass_OP::LT: return *l_c < *r_n ? bool_true : bool_false;
case Sass_OP::GTE: return *l_c < *r_n ? bool_false : bool_true;
case Sass_OP::LTE: return *l_c < *r_n || *l_c == *r_n ? bool_true : bool_false;
case Sass_OP::GT: return *l_c < *r_n || *l_c == *r_n ? bool_false : bool_true;
case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
return Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, b_in->pstate()); return Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, b_in->pstate());
default: break; default: break;
...@@ -1265,13 +1257,6 @@ namespace Sass { ...@@ -1265,13 +1257,6 @@ namespace Sass {
Expression_Ptr Eval::operator()(String_Constant_Ptr s) Expression_Ptr Eval::operator()(String_Constant_Ptr s)
{ {
if (!s->is_delayed() && name_to_color(s->value())) {
Color_Ptr c = SASS_MEMORY_COPY(name_to_color(s->value())); // copy
c->pstate(s->pstate());
c->disp(s->value());
c->is_delayed(true);
return c;
}
return s; return s;
} }
......
...@@ -246,7 +246,8 @@ namespace Sass { ...@@ -246,7 +246,8 @@ namespace Sass {
std::string str(prop->to_string(ctx.c_options)); std::string str(prop->to_string(ctx.c_options));
new_p = SASS_MEMORY_NEW(String_Constant, old_p->pstate(), str); new_p = SASS_MEMORY_NEW(String_Constant, old_p->pstate(), str);
} }
Expression_Obj value = d->value()->perform(&eval); Expression_Obj value = d->value();
if (value) value = value->perform(&eval);
Block_Obj bb = ab ? operator()(ab) : NULL; Block_Obj bb = ab ? operator()(ab) : NULL;
if (!bb) { if (!bb) {
if (!value || (value->is_invisible() && !d->is_important())) return 0; if (!value || (value->is_invisible() && !d->is_important())) return 0;
......
...@@ -342,13 +342,13 @@ namespace Sass { ...@@ -342,13 +342,13 @@ namespace Sass {
for(auto ext : exts) { for(auto ext : exts) {
rel_path = join_paths(base, "_" + name + ext); rel_path = join_paths(base, "_" + name + ext);
abs_path = join_paths(root, rel_path); abs_path = join_paths(root, rel_path);
if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path }); if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path, ext == ".css" });
} }
// next test plain name with exts // next test plain name with exts
for(auto ext : exts) { for(auto ext : exts) {
rel_path = join_paths(base, name + ext); rel_path = join_paths(base, name + ext);
abs_path = join_paths(root, rel_path); abs_path = join_paths(root, rel_path);
if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path }); if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path, ext == ".css" });
} }
// nothing found // nothing found
return includes; return includes;
......
...@@ -89,9 +89,14 @@ namespace Sass { ...@@ -89,9 +89,14 @@ namespace Sass {
public: public:
// resolved absolute path // resolved absolute path
std::string abs_path; std::string abs_path;
// is a deprecated file type
bool deprecated;
public: public:
Include(const Importer& imp, std::string abs_path, bool deprecated)
: Importer(imp), abs_path(abs_path), deprecated(deprecated)
{ }
Include(const Importer& imp, std::string abs_path) Include(const Importer& imp, std::string abs_path)
: Importer(imp), abs_path(abs_path) : Importer(imp), abs_path(abs_path), deprecated(false)
{ } { }
}; };
...@@ -121,11 +126,12 @@ namespace Sass { ...@@ -121,11 +126,12 @@ namespace Sass {
namespace File { namespace File {
static std::vector<std::string> defaultExtensions = { ".scss", ".sass", ".css" }; static std::vector<std::string> defaultExtensions = { ".scss", ".sass" };
std::vector<Include> resolve_includes(const std::string& root, const std::string& file, std::vector<Include> resolve_includes(const std::string& root, const std::string& file,
const std::vector<std::string>& exts = defaultExtensions); const std::vector<std::string>& exts = defaultExtensions);
} }
} }
......
...@@ -467,7 +467,7 @@ namespace Sass { ...@@ -467,7 +467,7 @@ namespace Sass {
double s; double s;
double l = (max + min) / 2.0; double l = (max + min) / 2.0;
if (max == min) { if (NEAR_EQUAL(max, min)) {
h = s = 0; // achromatic h = s = 0; // achromatic
} }
else { else {
......
...@@ -658,6 +658,9 @@ namespace Sass { ...@@ -658,6 +658,9 @@ namespace Sass {
} }
std::stringstream hexlet; std::stringstream hexlet;
// dart sass compressed all colors in regular css always
// ruby sass and libsass does it only when not delayed
// since color math is going to be removed, this can go too
bool compressed = opt.output_style == COMPRESSED; bool compressed = opt.output_style == COMPRESSED;
hexlet << '#' << std::setw(1) << std::setfill('0'); hexlet << '#' << std::setw(1) << std::setfill('0');
// create a short color hexlet if there is any need for it // create a short color hexlet if there is any need for it
...@@ -681,9 +684,6 @@ namespace Sass { ...@@ -681,9 +684,6 @@ namespace Sass {
if (name != "") { if (name != "") {
ss << name; ss << name;
} }
else if (r == 0 && g == 0 && b == 0 && a == 0) {
ss << "transparent";
}
else if (a >= 1) { else if (a >= 1) {
if (res_name != "") { if (res_name != "") {
if (compressed && hexlet.str().size() < res_name.size()) { if (compressed && hexlet.str().size() < res_name.size()) {
......
...@@ -127,15 +127,15 @@ namespace Sass { ...@@ -127,15 +127,15 @@ namespace Sass {
double lval = lhs.value(); double lval = lhs.value();
double rval = rhs.value(); double rval = rhs.value();
if (op == Sass_OP::MOD && rval == 0) {
return SASS_MEMORY_NEW(String_Quoted, pstate, "NaN");
}
if (op == Sass_OP::DIV && rval == 0) { if (op == Sass_OP::DIV && rval == 0) {
std::string result(lval ? "Infinity" : "NaN"); std::string result(lval ? "Infinity" : "NaN");
return SASS_MEMORY_NEW(String_Quoted, pstate, result); return SASS_MEMORY_NEW(String_Quoted, pstate, result);
} }
if (op == Sass_OP::MOD && rval == 0) {
throw Exception::ZeroDivisionError(lhs, rhs);
}
size_t l_n_units = lhs.numerators.size(); size_t l_n_units = lhs.numerators.size();
size_t l_d_units = lhs.numerators.size(); size_t l_d_units = lhs.numerators.size();
size_t r_n_units = rhs.denominators.size(); size_t r_n_units = rhs.denominators.size();
......
...@@ -1578,7 +1578,7 @@ namespace Sass { ...@@ -1578,7 +1578,7 @@ namespace Sass {
return nr; return nr;
} }
Expression_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed) Value_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed)
{ {
Color_Ptr color = NULL; Color_Ptr color = NULL;
if (parsed[0] != '#') { if (parsed[0] != '#') {
...@@ -1628,6 +1628,19 @@ namespace Sass { ...@@ -1628,6 +1628,19 @@ namespace Sass {
return color; return color;
} }
Value_Ptr Parser::color_or_string(const std::string& lexed) const
{
if (auto color = name_to_color(lexed)) {
auto c = SASS_MEMORY_NEW(Color, color);
c->is_delayed(true);
c->pstate(pstate);
c->disp(lexed);
return c;
} else {
return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
}
}
// parse one value for a list // parse one value for a list
Expression_Obj Parser::parse_value() Expression_Obj Parser::parse_value()
{ {
...@@ -1670,7 +1683,7 @@ namespace Sass { ...@@ -1670,7 +1683,7 @@ namespace Sass {
{ return SASS_MEMORY_NEW(Null, pstate); } { return SASS_MEMORY_NEW(Null, pstate); }
if (lex< identifier >()) { if (lex< identifier >()) {
return SASS_MEMORY_NEW(String_Constant, pstate, lexed); return color_or_string(lexed);
} }
if (lex< percentage >()) if (lex< percentage >())
...@@ -1841,7 +1854,7 @@ namespace Sass { ...@@ -1841,7 +1854,7 @@ namespace Sass {
return schema->length() > 0 ? schema.detach() : NULL; return schema->length() > 0 ? schema.detach() : NULL;
} }
String_Constant_Obj Parser::parse_static_value() Value_Obj Parser::parse_static_value()
{ {
lex< static_value >(); lex< static_value >();
Token str(lexed); Token str(lexed);
...@@ -1852,8 +1865,7 @@ namespace Sass { ...@@ -1852,8 +1865,7 @@ namespace Sass {
--str.end; --str.end;
--position; --position;
String_Constant_Ptr str_node = SASS_MEMORY_NEW(String_Constant, pstate, str.time_wspace()); return color_or_string(str.time_wspace());;
return str_node;
} }
String_Obj Parser::parse_string() String_Obj Parser::parse_string()
...@@ -1962,7 +1974,7 @@ namespace Sass { ...@@ -1962,7 +1974,7 @@ namespace Sass {
if (lex< re_static_expression >()) { if (lex< re_static_expression >()) {
ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed); ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
} else { } else {
ex = parse_list(); ex = parse_list(true);
} }
ex->is_interpolant(true); ex->is_interpolant(true);
schema->append(ex); schema->append(ex);
...@@ -1986,7 +1998,7 @@ namespace Sass { ...@@ -1986,7 +1998,7 @@ namespace Sass {
} }
if (peek < exactly < '-' > >()) break; if (peek < exactly < '-' > >()) break;
} }
else if (lex< sequence < identifier > >()) { else if (lex< identifier >()) {
schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed)); schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) { if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
// need_space = true; // need_space = true;
...@@ -2691,6 +2703,8 @@ namespace Sass { ...@@ -2691,6 +2703,8 @@ namespace Sass {
if ((rv = lex_interp_string())) return rv; if ((rv = lex_interp_string())) return rv;
if ((rv = lex_interp_uri())) return rv; if ((rv = lex_interp_uri())) return rv;
if ((rv = lex_interpolation())) return rv; if ((rv = lex_interpolation())) return rv;
if (lex< alternatives< hex, hex0 > >())
{ return lexed_hex_color(lexed); }
return rv; return rv;
} }
...@@ -2777,6 +2791,7 @@ namespace Sass { ...@@ -2777,6 +2791,7 @@ namespace Sass {
>(p) >(p)
) { ) {
bool could_be_property = peek< sequence< exactly<'-'>, exactly<'-'> > >(p) != 0; bool could_be_property = peek< sequence< exactly<'-'>, exactly<'-'> > >(p) != 0;
bool could_be_escaped = false;
while (p < q) { while (p < q) {
// did we have interpolations? // did we have interpolations?
if (*p == '#' && *(p+1) == '{') { if (*p == '#' && *(p+1) == '{') {
...@@ -2785,9 +2800,10 @@ namespace Sass { ...@@ -2785,9 +2800,10 @@ namespace Sass {
} }
// A property that's ambiguous with a nested selector is interpreted as a // A property that's ambiguous with a nested selector is interpreted as a
// custom property. // custom property.
if (*p == ':') { if (*p == ':' && !could_be_escaped) {
rv.is_custom_property = could_be_property || p+1 == q || peek< space >(p+1); rv.is_custom_property = could_be_property || p+1 == q || peek< space >(p+1);
} }
could_be_escaped = *p == '\\';
++ p; ++ p;
} }
// store anyway } // store anyway }
......
...@@ -290,7 +290,7 @@ namespace Sass { ...@@ -290,7 +290,7 @@ namespace Sass {
String_Obj parse_url_function_argument(); String_Obj parse_url_function_argument();
String_Obj parse_interpolated_chunk(Token, bool constant = false, bool css = true); String_Obj parse_interpolated_chunk(Token, bool constant = false, bool css = true);
String_Obj parse_string(); String_Obj parse_string();
String_Constant_Obj parse_static_value(); Value_Obj parse_static_value();
String_Schema_Obj parse_css_variable_value(bool top_level = true); String_Schema_Obj parse_css_variable_value(bool top_level = true);
String_Schema_Obj parse_css_variable_value_token(bool top_level = true); String_Schema_Obj parse_css_variable_value_token(bool top_level = true);
String_Obj parse_ie_property(); String_Obj parse_ie_property();
...@@ -325,6 +325,8 @@ namespace Sass { ...@@ -325,6 +325,8 @@ namespace Sass {
Error_Obj parse_error(); Error_Obj parse_error();
Debug_Obj parse_debug(); Debug_Obj parse_debug();
Value_Ptr color_or_string(const std::string& lexed) const;
// be more like ruby sass // be more like ruby sass
Expression_Obj lex_almost_any_value_token(); Expression_Obj lex_almost_any_value_token();
Expression_Obj lex_almost_any_value_chars(); Expression_Obj lex_almost_any_value_chars();
...@@ -380,12 +382,12 @@ namespace Sass { ...@@ -380,12 +382,12 @@ namespace Sass {
static Number_Ptr lexed_number(const ParserState& pstate, const std::string& parsed); static Number_Ptr lexed_number(const ParserState& pstate, const std::string& parsed);
static Number_Ptr lexed_dimension(const ParserState& pstate, const std::string& parsed); static Number_Ptr lexed_dimension(const ParserState& pstate, const std::string& parsed);
static Number_Ptr lexed_percentage(const ParserState& pstate, const std::string& parsed); static Number_Ptr lexed_percentage(const ParserState& pstate, const std::string& parsed);
static Expression_Ptr lexed_hex_color(const ParserState& pstate, const std::string& parsed); static Value_Ptr lexed_hex_color(const ParserState& pstate, const std::string& parsed);
private: private:
Number_Ptr lexed_number(const std::string& parsed) { return lexed_number(pstate, parsed); }; Number_Ptr lexed_number(const std::string& parsed) { return lexed_number(pstate, parsed); };
Number_Ptr lexed_dimension(const std::string& parsed) { return lexed_dimension(pstate, parsed); }; Number_Ptr lexed_dimension(const std::string& parsed) { return lexed_dimension(pstate, parsed); };
Number_Ptr lexed_percentage(const std::string& parsed) { return lexed_percentage(pstate, parsed); }; Number_Ptr lexed_percentage(const std::string& parsed) { return lexed_percentage(pstate, parsed); };
Expression_Ptr lexed_hex_color(const std::string& parsed) { return lexed_hex_color(pstate, parsed); }; Value_Ptr lexed_hex_color(const std::string& parsed) { return lexed_hex_color(pstate, parsed); };
static const char* re_attr_sensitive_close(const char* src); static const char* re_attr_sensitive_close(const char* src);
static const char* re_attr_insensitive_close(const char* src); static const char* re_attr_insensitive_close(const char* src);
......
...@@ -1606,7 +1606,7 @@ namespace Sass { ...@@ -1606,7 +1606,7 @@ namespace Sass {
>(src); >(src);
} }
extern const char css_variable_url_top_level_negates[] = "()[]{}\"'#/;!"; extern const char css_variable_url_top_level_negates[] = "()[]{}\"'#/;";
const char* css_variable_top_level_value(const char* src) { const char* css_variable_top_level_value(const char* src) {
return sequence< return sequence<
alternatives< alternatives<
......
...@@ -33,8 +33,10 @@ extern "C" { ...@@ -33,8 +33,10 @@ extern "C" {
void* ADDCALL sass_alloc_memory(size_t size) void* ADDCALL sass_alloc_memory(size_t size)
{ {
void* ptr = malloc(size); void* ptr = malloc(size);
if (ptr == NULL) if (ptr == NULL) {
out_of_memory(); std::cerr << "Out of memory.\n";
exit(EXIT_FAILURE);
}
return ptr; return ptr;
} }
......
...@@ -154,6 +154,21 @@ namespace Sass ...@@ -154,6 +154,21 @@ namespace Sass
} }
static size_t findFirstCharacter (std::string& sass, size_t pos)
{
return sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos);
}
static size_t findLastCharacter (std::string& sass, size_t pos)
{
return sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE, pos);
}
static bool isUrl (std::string& sass, size_t pos)
{
return sass[pos] == 'u' && sass[pos+1] == 'r' && sass[pos+2] == 'l' && sass[pos+3] == '(';
}
// check if there is some char data // check if there is some char data
// will ignore everything in comments // will ignore everything in comments
static bool hasCharData (std::string& sass) static bool hasCharData (std::string& sass)
...@@ -587,6 +602,7 @@ namespace Sass ...@@ -587,6 +602,7 @@ namespace Sass
sass.substr(pos_left, 5) == "@warn" || sass.substr(pos_left, 5) == "@warn" ||
sass.substr(pos_left, 6) == "@debug" || sass.substr(pos_left, 6) == "@debug" ||
sass.substr(pos_left, 6) == "@error" || sass.substr(pos_left, 6) == "@error" ||
sass.substr(pos_left, 6) == "@value" ||
sass.substr(pos_left, 8) == "@charset" || sass.substr(pos_left, 8) == "@charset" ||
sass.substr(pos_left, 10) == "@namespace" sass.substr(pos_left, 10) == "@namespace"
) { sass = indent + sass.substr(pos_left); } ) { sass = indent + sass.substr(pos_left); }
...@@ -606,23 +622,38 @@ namespace Sass ...@@ -606,23 +622,38 @@ namespace Sass
{ {
// get positions for the actual import url // get positions for the actual import url
size_t pos_import = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left + 7); size_t pos_import = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left + 7);
size_t pos_quote = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_import); size_t pos = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_import);
// leave proper urls untouched size_t start = pos;
if (sass.substr(pos_quote, 4) != "url(") bool in_dqstr = false;
{ bool in_sqstr = false;
// check if the url appears to be already quoted bool is_escaped = false;
if (sass.substr(pos_quote, 1) != "\"" && sass.substr(pos_quote, 1) != "\'") do {
{ if (is_escaped) {
// get position of the last char on the line is_escaped = false;
size_t pos_end = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE); }
// assertion check for valid result else if (sass[pos] == '\\') {
if (pos_end != std::string::npos) is_escaped = true;
{ }
// add quotes around the full line after the import statement else if (sass[pos] == '"') {
sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\""; if (!in_sqstr) in_dqstr = ! in_dqstr;
}
else if (sass[pos] == '\'') {
if (!in_dqstr) in_sqstr = ! in_sqstr;
}
else if (in_dqstr || in_sqstr) {
// skip over quoted stuff
}
else if (sass[pos] == ',' || sass[pos] == 0) {
if (sass[start] != '"' && sass[start] != '\'' && !isUrl(sass, start)) {
size_t end = findLastCharacter(sass, pos - 1) + 1;
sass = sass.replace(end, 0, "\"");
sass = sass.replace(start, 0, "\"");
pos += 2;
} }
start = findFirstCharacter(sass, pos + 1);
} }
} }
while (sass[pos++] != 0);
} }
else if ( else if (
......
...@@ -524,6 +524,7 @@ extern "C" { ...@@ -524,6 +524,7 @@ extern "C" {
options->c_headers = 0; options->c_headers = 0;
options->plugin_paths = 0; options->plugin_paths = 0;
options->include_paths = 0; options->include_paths = 0;
options->extensions = 0;
} }
// helper function, not exported, only accessible locally // helper function, not exported, only accessible locally
...@@ -558,6 +559,18 @@ extern "C" { ...@@ -558,6 +559,18 @@ extern "C" {
cur = next; cur = next;
} }
} }
// Deallocate extension
if (options->extensions) {
struct string_list* cur;
struct string_list* next;
cur = options->extensions;
while (cur) {
next = cur->next;
free(cur->string);
free(cur);
cur = next;
}
}
// Free options strings // Free options strings
free(options->input_path); free(options->input_path);
free(options->output_path); free(options->output_path);
...@@ -577,6 +590,7 @@ extern "C" { ...@@ -577,6 +590,7 @@ extern "C" {
options->c_headers = 0; options->c_headers = 0;
options->plugin_paths = 0; options->plugin_paths = 0;
options->include_paths = 0; options->include_paths = 0;
options->extensions = 0;
} }
// helper function, not exported, only accessible locally // helper function, not exported, only accessible locally
...@@ -713,6 +727,22 @@ extern "C" { ...@@ -713,6 +727,22 @@ extern "C" {
IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string); IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string);
IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files); IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files);
// Push function for import extenions
void ADDCALL sass_option_push_import_extension(struct Sass_Options* options, const char* ext)
{
struct string_list* extension = (struct string_list*) calloc(1, sizeof(struct string_list));
if (extension == 0) return;
extension->string = ext ? sass_copy_c_string(ext) : 0;
struct string_list* last = options->extensions;
if (!options->extensions) {
options->extensions = extension;
} else {
while (last->next)
last = last->next;
last->next = extension;
}
}
// Push function for include paths (no manipulation support for now) // Push function for include paths (no manipulation support for now)
void ADDCALL sass_option_push_include_path(struct Sass_Options* options, const char* path) void ADDCALL sass_option_push_include_path(struct Sass_Options* options, const char* path)
{ {
......
...@@ -40,9 +40,12 @@ struct Sass_Options : Sass_Output_Options { ...@@ -40,9 +40,12 @@ struct Sass_Options : Sass_Output_Options {
// Colon-separated list of paths // Colon-separated list of paths
// Semicolon-separated on Windows // Semicolon-separated on Windows
// Maybe use array interface instead? // Maybe use array interface instead?
char* extension;
char* include_path; char* include_path;
char* plugin_path; char* plugin_path;
// Extensions (linked string list)
struct string_list* extensions;
// Include paths (linked string list) // Include paths (linked string list)
struct string_list* include_paths; struct string_list* include_paths;
// Plugin paths (linked string list) // Plugin paths (linked string list)
......
...@@ -12,11 +12,6 @@ ...@@ -12,11 +12,6 @@
namespace Sass { namespace Sass {
#define out_of_memory() do { \
std::cerr << "Out of memory.\n"; \
exit(EXIT_FAILURE); \
} while (0)
double round(double val, size_t precision = 0); double round(double val, size_t precision = 0);
double sass_strtod(const char* str); double sass_strtod(const char* str);
const char* safe_str(const char *, const char* = ""); const char* safe_str(const char *, const char* = "");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment