From 9c711ee3deb65d196bf9634a4caae3252b6e8969 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Jul 2014 13:03:25 +0200 Subject: [PATCH 1/9] Fixes regressions introduces in previous merges aa023009a72a39a26bf705f6853cdadb4853fba9 - omit_source_map_url 61edd1457dcaeb70e1ecfc225b43891e12450fae - FS Case Sensitivity --- context.cpp | 8 ++++++-- file.cpp | 33 ++++++++++++++++----------------- file.hpp | 2 +- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/context.cpp b/context.cpp index b33fe2b8b2..3033a15ecb 100644 --- a/context.cpp +++ b/context.cpp @@ -234,7 +234,9 @@ namespace Sass { Output_Compressed output_compressed(this); root->perform(&output_compressed); string output = output_compressed.get_buffer(); - if (!omit_source_map_url) output += format_source_mapping_url(source_map_file); + if (source_map_file != "" && !omit_source_map_url) { + output += format_source_mapping_url(source_map_file); + } result = copy_c_str(output.c_str()); } break; @@ -242,7 +244,9 @@ namespace Sass { Output_Nested output_nested(source_comments, this); root->perform(&output_nested); string output = output_nested.get_buffer(); - if (!omit_source_map_url) output += "\n" + format_source_mapping_url(source_map_file); + if (source_map_file != "" && !omit_source_map_url) { + output += "\n" + format_source_mapping_url(source_map_file); + } result = copy_c_str(output.c_str()); } break; diff --git a/file.cpp b/file.cpp index 0f3def0ce2..c807072f3e 100644 --- a/file.cpp +++ b/file.cpp @@ -2,6 +2,14 @@ #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #endif +#ifndef FS_CASE_SENSITIVE +#ifdef _WIN32 +#define FS_CASE_SENSITIVE 0 +#else +#define FS_CASE_SENSITIVE 1 +#endif +#endif + #include #include #include @@ -82,23 +90,8 @@ namespace Sass { return (is_absolute_path(path) ? path : join_paths(cwd, path)); } - string resolve_relative_path(const string& uri, const string& base, const string& cwd, const bool recurse) + string resolve_relative_path(const string& uri, const string& base, const string& cwd) { - if (!recurse) { - #ifdef _WIN32 - // Convert all paths to lower case for Windows - string uri2(uri); - transform(uri.begin(), uri.end(), uri2.begin(), tolower); - - string base2(base); - transform(base.begin(), base.end(), base2.begin(), tolower); - - string cwd2(cwd); - transform(cwd.begin(), cwd.end(), cwd2.begin(), tolower); - - return resolve_relative_path(uri2, base2, cwd2, true); - #endif - } string absolute_uri = make_absolute_path(uri, cwd); string absolute_base = make_absolute_path(base, cwd); @@ -109,7 +102,13 @@ namespace Sass { size_t index = 0; size_t minSize = min(absolute_uri.size(), absolute_base.size()); for (size_t i = 0; i < minSize; ++i) { - if (absolute_uri[i] != absolute_base[i]) break; + #ifdef FS_CASE_SENSITIVE + if (absolute_uri[i] != absolute_base[i]) break; + #else + // compare the charactes in a case insensitive manner + // windows fs is only case insensitive in ascii ranges + if (tolower(absolute_uri[i]) != tolower(absolute_base[i])) break; + #endif if (absolute_uri[i] == '/') index = i + 1; } for (size_t i = index; i < absolute_uri.size(); ++i) { diff --git a/file.hpp b/file.hpp index 6fd8e93b8a..e095040cda 100644 --- a/file.hpp +++ b/file.hpp @@ -9,7 +9,7 @@ namespace Sass { string join_paths(string, string); bool is_absolute_path(const string& path); string make_absolute_path(const string& path, const string& cwd); - string resolve_relative_path(const string& uri, const string& base, const string& cwd, const bool recurse=false); + string resolve_relative_path(const string& uri, const string& base, const string& cwd); char* resolve_and_load(string path, string& real_path); char* read_file(string path); } From 628478a9c3bfba94163dc0e9fac217fa4d5876c0 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Jul 2014 17:54:43 +0200 Subject: [PATCH 2/9] Moves path normalization before trailing slash test --- context.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/context.cpp b/context.cpp index 3033a15ecb..c72e4bb01a 100644 --- a/context.cpp +++ b/context.cpp @@ -289,10 +289,11 @@ namespace Sass { const size_t wd_len = 1024; char wd[wd_len]; string cwd = getcwd(wd, wd_len); - if (cwd[cwd.length() - 1] != '/') cwd += '/'; #ifdef _WIN32 - replace(cwd.begin(), cwd.end(), '\\', '/'); //convert Windows backslashes to URL forward slashes + //convert backslashes to forward slashes + replace(cwd.begin(), cwd.end(), '\\', '/'); #endif + if (cwd[cwd.length() - 1] != '/') cwd += '/'; return cwd; } From e758d8d1371ead2a68c874801328088d14e79371 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Jul 2014 19:39:15 +0200 Subject: [PATCH 3/9] Adds canonical_path helper function Note that this does *not* collapse x/../y sections into y. This is by design. If /foo on your system is a symlink to /bar/baz, then /foo/../quux is actually /bar/quux, not /quux as a naive ../-removal would give you. --- file.cpp | 29 ++++++++++++++++++++++++++++- file.hpp | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/file.cpp b/file.cpp index c807072f3e..42431dedf0 100644 --- a/file.cpp +++ b/file.cpp @@ -23,6 +23,33 @@ namespace Sass { namespace File { using namespace std; + // no physical check on filesystem + // only a logical cleanup of a path + string make_canonical_path (string path) + { + + // declarations + size_t pos; + + #ifdef _WIN32 + //convert backslashes to forward slashes + replace(path.begin(), path.end(), '\\', '/'); + #endif + + pos = 0; // remove all self references inside the path string + while((pos = path.find("/./", pos)) != string::npos) path.erase(pos, 2); + + pos = 0; // remove all leading and trailing self references + while(path.length() > 1 && path.substr(0, 2) == "./") path.erase(0, 2); + while((pos = path.length()) > 1 && path.substr(pos - 2) == "/.") path.erase(pos - 2); + + pos = 0; // collapse multiple delimiters into a single one + while((pos = path.find("//", pos)) != string::npos) path.replace(pos, 2, "/"); + + return path; + + } + size_t find_last_folder_separator(const string& path, size_t limit = string::npos) { size_t pos = string::npos; @@ -87,7 +114,7 @@ namespace Sass { string make_absolute_path(const string& path, const string& cwd) { - return (is_absolute_path(path) ? path : join_paths(cwd, path)); + return make_canonical_path((is_absolute_path(path) ? path : join_paths(cwd, path))); } string resolve_relative_path(const string& uri, const string& base, const string& cwd) diff --git a/file.hpp b/file.hpp index e095040cda..8917e0fbe9 100644 --- a/file.hpp +++ b/file.hpp @@ -8,6 +8,7 @@ namespace Sass { string dir_name(string); string join_paths(string, string); bool is_absolute_path(const string& path); + string make_canonical_path (string path); string make_absolute_path(const string& path, const string& cwd); string resolve_relative_path(const string& uri, const string& base, const string& cwd); char* resolve_and_load(string path, string& real_path); From a388b8f128a70d4cbfdfa97129d493a7989a046c Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Jul 2014 19:59:27 +0200 Subject: [PATCH 4/9] Implements relative sourceMappingURL handling Adds canonical file resolving where appropriate. It might should be noted that output_path does not mean that libsass will write the result to that location. It is merely used to create file paths relative to the output file (which defaults to input_path with a 'css' extension). --- context.cpp | 11 +++++++---- context.hpp | 1 + sass.cpp | 4 ++++ sass.h | 1 + 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/context.cpp b/context.cpp index c72e4bb01a..110489f483 100644 --- a/context.cpp +++ b/context.cpp @@ -48,13 +48,14 @@ namespace Sass { include_paths (initializers.include_paths()), queue (vector >()), style_sheets (map()), - source_map (File::base_name(initializers.output_path())), + source_map (File::make_canonical_path(initializers.output_path())), c_functions (vector()), - image_path (initializers.image_path()), + image_path (File::make_canonical_path(initializers.image_path())), + output_path (File::make_canonical_path(initializers.output_path())), source_comments (initializers.source_comments()), source_maps (initializers.source_maps()), output_style (initializers.output_style()), - source_map_file (initializers.source_map_file()), + source_map_file (File::make_canonical_path(initializers.source_map_file())), omit_source_map_url (initializers.omit_source_map_url()), names_to_colors (map()), colors_to_names (map()), @@ -146,6 +147,7 @@ namespace Sass { using namespace File; char* contents = 0; string real_path; + path = make_canonical_path(path); for (size_t i = 0, S = include_paths.size(); i < S; ++i) { string full_path(join_paths(include_paths[i], path)); included_files.push_back(full_path); @@ -168,6 +170,7 @@ namespace Sass { using namespace File; char* contents = 0; string real_path; + rel_filepath = make_canonical_path(rel_filepath); string full_path(join_paths(dir, rel_filepath)); if (style_sheets.count(full_path)) return full_path; contents = resolve_and_load(full_path, real_path); @@ -257,7 +260,7 @@ namespace Sass { string Context::format_source_mapping_url(const string& file) const { - return "/*# sourceMappingURL=" + File::base_name(file) + " */"; + return "/*# sourceMappingURL=" + File::resolve_relative_path(file, output_path, cwd) + " */"; } char* Context::generate_source_map() diff --git a/context.hpp b/context.hpp index 823b43d5ce..1b8fb9be62 100644 --- a/context.hpp +++ b/context.hpp @@ -49,6 +49,7 @@ namespace Sass { vector c_functions; string image_path; // for the image-url Sass function + string output_path; // for relative paths to the output bool source_comments; bool source_maps; Output_Style output_style; diff --git a/sass.cpp b/sass.cpp index d76f5fb8de..fb9f44fe93 100644 --- a/sass.cpp +++ b/sass.cpp @@ -51,6 +51,10 @@ extern "C" { c_ctx->image_path : "") + .output_path (c_ctx->output_path ? + c_ctx->output_path : + "") + .include_paths_c_str (c_ctx->include_paths_string) .include_paths_array (/*c_ctx->include_paths_array*/0) .include_paths (vector()) diff --git a/sass.h b/sass.h index b7782da923..d313d3f8e0 100644 --- a/sass.h +++ b/sass.h @@ -24,6 +24,7 @@ struct Sass_Context { int source_comments; int source_maps; const char* image_path; + const char* output_path; const char* include_paths_string; const char** include_paths_array; int precision; From 5980677eb44cb36d9c98f7ebfc49f0173d3dd0e2 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Jul 2014 20:59:55 +0200 Subject: [PATCH 5/9] Improves resolve_relative_path to handle parent references Accounts for parent references (`..`) in `stripped_base`. --- file.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/file.cpp b/file.cpp index 42431dedf0..2452938d70 100644 --- a/file.cpp +++ b/file.cpp @@ -144,10 +144,24 @@ namespace Sass { for (size_t i = index; i < absolute_base.size(); ++i) { stripped_base += absolute_base[i]; } + + size_t left = 0; size_t directories = 0; - for (size_t i = 0; i < stripped_base.size(); ++i) { - if (stripped_base[i] == '/') ++directories; + for (size_t right = 0; right < stripped_base.size(); ++right) { + if (stripped_base[right] == '/') { + if (stripped_base.substr(left, 2) != "..") { + ++directories; + } + else if (directories > 1) { + --directories; + } + else { + directories = 0; + } + left = right + 1; + } } + string result = ""; for (size_t i = 0; i < directories; ++i) { result += "../"; From 216a40c7ec531e943c56d3affd161f799e24be8d Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Jul 2014 21:28:00 +0200 Subject: [PATCH 6/9] Tweaks `make_canonical_path` for better performance --- file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/file.cpp b/file.cpp index 2452938d70..b583643770 100644 --- a/file.cpp +++ b/file.cpp @@ -44,7 +44,7 @@ namespace Sass { while((pos = path.length()) > 1 && path.substr(pos - 2) == "/.") path.erase(pos - 2); pos = 0; // collapse multiple delimiters into a single one - while((pos = path.find("//", pos)) != string::npos) path.replace(pos, 2, "/"); + while((pos = path.find("//", pos)) != string::npos) path.erase(pos, 1); return path; From 2f2f0db3d6f6bc7474c6a51fdb97f44121565358 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Jul 2014 22:13:05 +0200 Subject: [PATCH 7/9] Improves source map output on `compile_string` Add a source entry for stdin. This mimics exactly the behavior of the Google Closure Compiler on stdin data. --- context.cpp | 2 ++ sass_interface.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/context.cpp b/context.cpp index 110489f483..68387d7807 100644 --- a/context.cpp +++ b/context.cpp @@ -277,6 +277,8 @@ namespace Sass { if (!source_c_str) return 0; queue.clear(); queue.push_back(make_pair("source string", source_c_str)); + // mimic google closure compiler + source_map.files.push_back("stdin"); return compile_file(); } diff --git a/sass_interface.cpp b/sass_interface.cpp index a6aa780ed1..da1aa10493 100644 --- a/sass_interface.cpp +++ b/sass_interface.cpp @@ -97,7 +97,9 @@ extern "C" { int lastindex = input_path.find_last_of("."); string output_path; if (!c_ctx->output_path) { + if (input_path != "") { output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css"; + } } else { output_path = c_ctx->output_path; From e01ea97ac60589d99427a780807d1d49b5052aa6 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Wed, 30 Jul 2014 00:12:41 +0200 Subject: [PATCH 8/9] Initializes SourceMap with path relative to output Points to working directory (ending with a slash) if no input file path has been given (i.e. on 'compile_string'). --- context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context.cpp b/context.cpp index 68387d7807..33de376512 100644 --- a/context.cpp +++ b/context.cpp @@ -48,7 +48,7 @@ namespace Sass { include_paths (initializers.include_paths()), queue (vector >()), style_sheets (map()), - source_map (File::make_canonical_path(initializers.output_path())), + source_map (File::resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())), c_functions (vector()), image_path (File::make_canonical_path(initializers.image_path())), output_path (File::make_canonical_path(initializers.output_path())), From 029c86faa84623e04198e02948a0a43d7de814a4 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Wed, 30 Jul 2014 00:14:32 +0200 Subject: [PATCH 9/9] Uses Sass::File namespace --- context.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/context.cpp b/context.cpp index 33de376512..a74ddaeac5 100644 --- a/context.cpp +++ b/context.cpp @@ -38,6 +38,7 @@ namespace Sass { using namespace Constants; + using namespace File; using std::cerr; using std::endl; @@ -48,14 +49,14 @@ namespace Sass { include_paths (initializers.include_paths()), queue (vector >()), style_sheets (map()), - source_map (File::resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())), + source_map (resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())), c_functions (vector()), - image_path (File::make_canonical_path(initializers.image_path())), - output_path (File::make_canonical_path(initializers.output_path())), + image_path (make_canonical_path(initializers.image_path())), + output_path (make_canonical_path(initializers.output_path())), source_comments (initializers.source_comments()), source_maps (initializers.source_maps()), output_style (initializers.output_style()), - source_map_file (File::make_canonical_path(initializers.source_map_file())), + source_map_file (make_canonical_path(initializers.source_map_file())), omit_source_map_url (initializers.omit_source_map_url()), names_to_colors (map()), colors_to_names (map()), @@ -260,7 +261,7 @@ namespace Sass { string Context::format_source_mapping_url(const string& file) const { - return "/*# sourceMappingURL=" + File::resolve_relative_path(file, output_path, cwd) + " */"; + return "/*# sourceMappingURL=" + resolve_relative_path(file, output_path, cwd) + " */"; } char* Context::generate_source_map()