diff --git a/context.cpp b/context.cpp index b33fe2b8b2..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,13 +49,14 @@ namespace Sass { include_paths (initializers.include_paths()), queue (vector >()), style_sheets (map()), - source_map (File::base_name(initializers.output_path())), + source_map (resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())), c_functions (vector()), - image_path (initializers.image_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 (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()), @@ -146,6 +148,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 +171,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); @@ -234,7 +238,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 +248,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; @@ -253,7 +261,7 @@ namespace Sass { string Context::format_source_mapping_url(const string& file) const { - return "/*# sourceMappingURL=" + File::base_name(file) + " */"; + return "/*# sourceMappingURL=" + resolve_relative_path(file, output_path, cwd) + " */"; } char* Context::generate_source_map() @@ -270,6 +278,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(); } @@ -285,10 +295,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; } 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/file.cpp b/file.cpp index 0f3def0ce2..b583643770 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 @@ -15,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.erase(pos, 1); + + return path; + + } + size_t find_last_folder_separator(const string& path, size_t limit = string::npos) { size_t pos = string::npos; @@ -79,26 +114,11 @@ 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, 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 +129,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) { @@ -118,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 += "../"; diff --git a/file.hpp b/file.hpp index 6fd8e93b8a..8917e0fbe9 100644 --- a/file.hpp +++ b/file.hpp @@ -8,8 +8,9 @@ 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, 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); } 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; 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;