sassc4 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +16 -0
  5. data/CHANGELOG.md +97 -0
  6. data/CODE_OF_CONDUCT.md +10 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +80 -0
  10. data/Rakefile +51 -0
  11. data/ext/depend +4 -0
  12. data/ext/extconf.rb +92 -0
  13. data/ext/libsass/VERSION +1 -0
  14. data/ext/libsass/contrib/plugin.cpp +60 -0
  15. data/ext/libsass/include/sass/base.h +97 -0
  16. data/ext/libsass/include/sass/context.h +174 -0
  17. data/ext/libsass/include/sass/functions.h +139 -0
  18. data/ext/libsass/include/sass/values.h +145 -0
  19. data/ext/libsass/include/sass/version.h +12 -0
  20. data/ext/libsass/include/sass.h +15 -0
  21. data/ext/libsass/include/sass2scss.h +120 -0
  22. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  23. data/ext/libsass/src/ast.cpp +953 -0
  24. data/ext/libsass/src/ast.hpp +1064 -0
  25. data/ext/libsass/src/ast2c.cpp +80 -0
  26. data/ext/libsass/src/ast2c.hpp +39 -0
  27. data/ext/libsass/src/ast_def_macros.hpp +140 -0
  28. data/ext/libsass/src/ast_fwd_decl.cpp +31 -0
  29. data/ext/libsass/src/ast_fwd_decl.hpp +274 -0
  30. data/ext/libsass/src/ast_helpers.hpp +316 -0
  31. data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
  32. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  33. data/ext/libsass/src/ast_sel_unify.cpp +275 -0
  34. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  35. data/ext/libsass/src/ast_selectors.cpp +1070 -0
  36. data/ext/libsass/src/ast_selectors.hpp +523 -0
  37. data/ext/libsass/src/ast_supports.cpp +114 -0
  38. data/ext/libsass/src/ast_supports.hpp +121 -0
  39. data/ext/libsass/src/ast_values.cpp +1154 -0
  40. data/ext/libsass/src/ast_values.hpp +498 -0
  41. data/ext/libsass/src/b64/cencode.h +32 -0
  42. data/ext/libsass/src/b64/encode.h +79 -0
  43. data/ext/libsass/src/backtrace.cpp +50 -0
  44. data/ext/libsass/src/backtrace.hpp +29 -0
  45. data/ext/libsass/src/base64vlq.cpp +47 -0
  46. data/ext/libsass/src/base64vlq.hpp +30 -0
  47. data/ext/libsass/src/bind.cpp +312 -0
  48. data/ext/libsass/src/bind.hpp +15 -0
  49. data/ext/libsass/src/c2ast.cpp +64 -0
  50. data/ext/libsass/src/c2ast.hpp +14 -0
  51. data/ext/libsass/src/c99func.c +54 -0
  52. data/ext/libsass/src/cencode.c +106 -0
  53. data/ext/libsass/src/check_nesting.cpp +393 -0
  54. data/ext/libsass/src/check_nesting.hpp +70 -0
  55. data/ext/libsass/src/color_maps.cpp +652 -0
  56. data/ext/libsass/src/color_maps.hpp +323 -0
  57. data/ext/libsass/src/color_spaces.cpp +241 -0
  58. data/ext/libsass/src/color_spaces.hpp +227 -0
  59. data/ext/libsass/src/constants.cpp +199 -0
  60. data/ext/libsass/src/constants.hpp +200 -0
  61. data/ext/libsass/src/context.cpp +870 -0
  62. data/ext/libsass/src/context.hpp +140 -0
  63. data/ext/libsass/src/cssize.cpp +521 -0
  64. data/ext/libsass/src/cssize.hpp +71 -0
  65. data/ext/libsass/src/dart_helpers.hpp +199 -0
  66. data/ext/libsass/src/debug.hpp +43 -0
  67. data/ext/libsass/src/debugger.hpp +964 -0
  68. data/ext/libsass/src/emitter.cpp +297 -0
  69. data/ext/libsass/src/emitter.hpp +101 -0
  70. data/ext/libsass/src/environment.cpp +260 -0
  71. data/ext/libsass/src/environment.hpp +124 -0
  72. data/ext/libsass/src/error_handling.cpp +239 -0
  73. data/ext/libsass/src/error_handling.hpp +248 -0
  74. data/ext/libsass/src/eval.cpp +1543 -0
  75. data/ext/libsass/src/eval.hpp +110 -0
  76. data/ext/libsass/src/eval_selectors.cpp +75 -0
  77. data/ext/libsass/src/expand.cpp +875 -0
  78. data/ext/libsass/src/expand.hpp +98 -0
  79. data/ext/libsass/src/extender.cpp +1226 -0
  80. data/ext/libsass/src/extender.hpp +399 -0
  81. data/ext/libsass/src/extension.cpp +43 -0
  82. data/ext/libsass/src/extension.hpp +89 -0
  83. data/ext/libsass/src/file.cpp +531 -0
  84. data/ext/libsass/src/file.hpp +124 -0
  85. data/ext/libsass/src/fn_colors.cpp +836 -0
  86. data/ext/libsass/src/fn_colors.hpp +99 -0
  87. data/ext/libsass/src/fn_lists.cpp +285 -0
  88. data/ext/libsass/src/fn_lists.hpp +34 -0
  89. data/ext/libsass/src/fn_maps.cpp +94 -0
  90. data/ext/libsass/src/fn_maps.hpp +30 -0
  91. data/ext/libsass/src/fn_miscs.cpp +248 -0
  92. data/ext/libsass/src/fn_miscs.hpp +40 -0
  93. data/ext/libsass/src/fn_numbers.cpp +246 -0
  94. data/ext/libsass/src/fn_numbers.hpp +45 -0
  95. data/ext/libsass/src/fn_selectors.cpp +205 -0
  96. data/ext/libsass/src/fn_selectors.hpp +35 -0
  97. data/ext/libsass/src/fn_strings.cpp +268 -0
  98. data/ext/libsass/src/fn_strings.hpp +34 -0
  99. data/ext/libsass/src/fn_utils.cpp +159 -0
  100. data/ext/libsass/src/fn_utils.hpp +62 -0
  101. data/ext/libsass/src/inspect.cpp +1126 -0
  102. data/ext/libsass/src/inspect.hpp +101 -0
  103. data/ext/libsass/src/json.cpp +1436 -0
  104. data/ext/libsass/src/json.hpp +117 -0
  105. data/ext/libsass/src/kwd_arg_macros.hpp +28 -0
  106. data/ext/libsass/src/lexer.cpp +122 -0
  107. data/ext/libsass/src/lexer.hpp +304 -0
  108. data/ext/libsass/src/listize.cpp +70 -0
  109. data/ext/libsass/src/listize.hpp +37 -0
  110. data/ext/libsass/src/mapping.hpp +19 -0
  111. data/ext/libsass/src/memory/allocator.cpp +48 -0
  112. data/ext/libsass/src/memory/allocator.hpp +138 -0
  113. data/ext/libsass/src/memory/config.hpp +20 -0
  114. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  115. data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
  116. data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
  117. data/ext/libsass/src/memory.hpp +12 -0
  118. data/ext/libsass/src/operation.hpp +223 -0
  119. data/ext/libsass/src/operators.cpp +267 -0
  120. data/ext/libsass/src/operators.hpp +30 -0
  121. data/ext/libsass/src/ordered_map.hpp +112 -0
  122. data/ext/libsass/src/output.cpp +320 -0
  123. data/ext/libsass/src/output.hpp +47 -0
  124. data/ext/libsass/src/parser.cpp +3059 -0
  125. data/ext/libsass/src/parser.hpp +395 -0
  126. data/ext/libsass/src/parser_selectors.cpp +189 -0
  127. data/ext/libsass/src/permutate.hpp +164 -0
  128. data/ext/libsass/src/plugins.cpp +188 -0
  129. data/ext/libsass/src/plugins.hpp +57 -0
  130. data/ext/libsass/src/position.cpp +163 -0
  131. data/ext/libsass/src/position.hpp +147 -0
  132. data/ext/libsass/src/prelexer.cpp +1780 -0
  133. data/ext/libsass/src/prelexer.hpp +484 -0
  134. data/ext/libsass/src/remove_placeholders.cpp +86 -0
  135. data/ext/libsass/src/remove_placeholders.hpp +37 -0
  136. data/ext/libsass/src/sass.cpp +156 -0
  137. data/ext/libsass/src/sass.hpp +147 -0
  138. data/ext/libsass/src/sass2scss.cpp +895 -0
  139. data/ext/libsass/src/sass_context.cpp +742 -0
  140. data/ext/libsass/src/sass_context.hpp +129 -0
  141. data/ext/libsass/src/sass_functions.cpp +210 -0
  142. data/ext/libsass/src/sass_functions.hpp +50 -0
  143. data/ext/libsass/src/sass_values.cpp +362 -0
  144. data/ext/libsass/src/sass_values.hpp +82 -0
  145. data/ext/libsass/src/settings.hpp +19 -0
  146. data/ext/libsass/src/source.cpp +69 -0
  147. data/ext/libsass/src/source.hpp +95 -0
  148. data/ext/libsass/src/source_data.hpp +32 -0
  149. data/ext/libsass/src/source_map.cpp +202 -0
  150. data/ext/libsass/src/source_map.hpp +65 -0
  151. data/ext/libsass/src/stylesheet.cpp +22 -0
  152. data/ext/libsass/src/stylesheet.hpp +57 -0
  153. data/ext/libsass/src/to_value.cpp +114 -0
  154. data/ext/libsass/src/to_value.hpp +46 -0
  155. data/ext/libsass/src/units.cpp +507 -0
  156. data/ext/libsass/src/units.hpp +110 -0
  157. data/ext/libsass/src/utf8/checked.h +336 -0
  158. data/ext/libsass/src/utf8/core.h +332 -0
  159. data/ext/libsass/src/utf8/unchecked.h +235 -0
  160. data/ext/libsass/src/utf8.h +34 -0
  161. data/ext/libsass/src/utf8_string.cpp +104 -0
  162. data/ext/libsass/src/utf8_string.hpp +38 -0
  163. data/ext/libsass/src/util.cpp +723 -0
  164. data/ext/libsass/src/util.hpp +105 -0
  165. data/ext/libsass/src/util_string.cpp +125 -0
  166. data/ext/libsass/src/util_string.hpp +73 -0
  167. data/ext/libsass/src/values.cpp +140 -0
  168. data/ext/libsass/src/values.hpp +12 -0
  169. data/lib/sassc/dependency.rb +17 -0
  170. data/lib/sassc/engine.rb +141 -0
  171. data/lib/sassc/error.rb +37 -0
  172. data/lib/sassc/functions_handler.rb +73 -0
  173. data/lib/sassc/import_handler.rb +50 -0
  174. data/lib/sassc/importer.rb +31 -0
  175. data/lib/sassc/native/native_context_api.rb +147 -0
  176. data/lib/sassc/native/native_functions_api.rb +159 -0
  177. data/lib/sassc/native/sass2scss_api.rb +10 -0
  178. data/lib/sassc/native/sass_input_style.rb +13 -0
  179. data/lib/sassc/native/sass_output_style.rb +12 -0
  180. data/lib/sassc/native/sass_value.rb +97 -0
  181. data/lib/sassc/native/string_list.rb +10 -0
  182. data/lib/sassc/native.rb +64 -0
  183. data/lib/sassc/sass_2_scss.rb +9 -0
  184. data/lib/sassc/script/functions.rb +8 -0
  185. data/lib/sassc/script/value/bool.rb +32 -0
  186. data/lib/sassc/script/value/color.rb +95 -0
  187. data/lib/sassc/script/value/list.rb +136 -0
  188. data/lib/sassc/script/value/map.rb +69 -0
  189. data/lib/sassc/script/value/number.rb +389 -0
  190. data/lib/sassc/script/value/string.rb +96 -0
  191. data/lib/sassc/script/value.rb +137 -0
  192. data/lib/sassc/script/value_conversion/base.rb +13 -0
  193. data/lib/sassc/script/value_conversion/bool.rb +13 -0
  194. data/lib/sassc/script/value_conversion/color.rb +18 -0
  195. data/lib/sassc/script/value_conversion/list.rb +25 -0
  196. data/lib/sassc/script/value_conversion/map.rb +21 -0
  197. data/lib/sassc/script/value_conversion/number.rb +13 -0
  198. data/lib/sassc/script/value_conversion/string.rb +17 -0
  199. data/lib/sassc/script/value_conversion.rb +69 -0
  200. data/lib/sassc/script.rb +17 -0
  201. data/lib/sassc/util/normalized_map.rb +117 -0
  202. data/lib/sassc/util.rb +231 -0
  203. data/lib/sassc/version.rb +5 -0
  204. data/lib/sassc.rb +57 -0
  205. data/sassc.gemspec +69 -0
  206. data/test/css_color_level4_test.rb +168 -0
  207. data/test/custom_importer_test.rb +127 -0
  208. data/test/engine_test.rb +314 -0
  209. data/test/error_test.rb +29 -0
  210. data/test/fixtures/paths.scss +10 -0
  211. data/test/functions_test.rb +340 -0
  212. data/test/native_test.rb +213 -0
  213. data/test/output_style_test.rb +107 -0
  214. data/test/sass_2_scss_test.rb +14 -0
  215. data/test/test_helper.rb +45 -0
  216. metadata +396 -0
@@ -0,0 +1,531 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+
5
+ #ifdef _WIN32
6
+ # ifdef __MINGW32__
7
+ # ifndef off64_t
8
+ # define off64_t _off64_t /* Workaround for http://sourceforge.net/p/mingw/bugs/2024/ */
9
+ # endif
10
+ # endif
11
+ # include <direct.h>
12
+ # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
13
+ #else
14
+ # include <unistd.h>
15
+ #endif
16
+ #include <cstdio>
17
+ #include <vector>
18
+ #include <algorithm>
19
+ #include <sys/stat.h>
20
+ #include "file.hpp"
21
+ #include "context.hpp"
22
+ #include "prelexer.hpp"
23
+ #include "utf8_string.hpp"
24
+ #include "sass_functions.hpp"
25
+ #include "error_handling.hpp"
26
+ #include "util.hpp"
27
+ #include "util_string.hpp"
28
+ #include "sass2scss.h"
29
+
30
+ #ifdef _WIN32
31
+ # include <windows.h>
32
+
33
+ # ifdef _MSC_VER
34
+ # include <codecvt>
35
+ inline static Sass::sass::string wstring_to_string(const std::wstring& wstr)
36
+ {
37
+ std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_converter;
38
+ return wchar_converter.to_bytes(wstr);
39
+ }
40
+ # else // mingw(/gcc) does not support C++11's codecvt yet.
41
+ inline static Sass::sass::string wstring_to_string(const std::wstring &wstr)
42
+ {
43
+ int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
44
+ Sass::sass::string strTo(size_needed, 0);
45
+ WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
46
+ return strTo;
47
+ }
48
+ # endif
49
+ #endif
50
+
51
+ namespace Sass {
52
+ namespace File {
53
+
54
+ // return the current directory
55
+ // always with forward slashes
56
+ // always with trailing slash
57
+ sass::string get_cwd()
58
+ {
59
+ const size_t wd_len = 4096;
60
+ #ifndef _WIN32
61
+ char wd[wd_len];
62
+ char* pwd = getcwd(wd, wd_len);
63
+ // we should check error for more detailed info (e.g. ENOENT)
64
+ // http://man7.org/linux/man-pages/man2/getcwd.2.html#ERRORS
65
+ if (pwd == NULL) throw Exception::OperationError("cwd gone missing");
66
+ sass::string cwd = pwd;
67
+ #else
68
+ wchar_t wd[wd_len];
69
+ wchar_t* pwd = _wgetcwd(wd, wd_len);
70
+ if (pwd == NULL) throw Exception::OperationError("cwd gone missing");
71
+ sass::string cwd = wstring_to_string(pwd);
72
+ //convert backslashes to forward slashes
73
+ replace(cwd.begin(), cwd.end(), '\\', '/');
74
+ #endif
75
+ if (cwd[cwd.length() - 1] != '/') cwd += '/';
76
+ return cwd;
77
+ }
78
+
79
+ // test if path exists and is a file
80
+ bool file_exists(const sass::string& path)
81
+ {
82
+ #ifdef _WIN32
83
+ wchar_t resolved[32768];
84
+ // windows unicode filepaths are encoded in utf16
85
+ sass::string abspath(join_paths(get_cwd(), path));
86
+ if (!(abspath[0] == '/' && abspath[1] == '/')) {
87
+ abspath = "//?/" + abspath;
88
+ }
89
+ std::wstring wpath(UTF_8::convert_to_utf16(abspath));
90
+ std::replace(wpath.begin(), wpath.end(), '/', '\\');
91
+ DWORD rv = GetFullPathNameW(wpath.c_str(), 32767, resolved, NULL);
92
+ if (rv > 32767) throw Exception::OperationError("Path is too long");
93
+ if (rv == 0) throw Exception::OperationError("Path could not be resolved");
94
+ DWORD dwAttrib = GetFileAttributesW(resolved);
95
+ return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
96
+ (!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
97
+ #else
98
+ struct stat st_buf;
99
+ return (stat (path.c_str(), &st_buf) == 0) &&
100
+ (!S_ISDIR (st_buf.st_mode));
101
+ #endif
102
+ }
103
+
104
+ // return if given path is absolute
105
+ // works with *nix and windows paths
106
+ bool is_absolute_path(const sass::string& path)
107
+ {
108
+ #ifdef _WIN32
109
+ if (path.length() >= 2 && Util::ascii_isalpha(path[0]) && path[1] == ':') return true;
110
+ #endif
111
+ size_t i = 0;
112
+ // check if we have a protocol
113
+ if (path[i] && Util::ascii_isalpha(static_cast<unsigned char>(path[i]))) {
114
+ // skip over all alphanumeric characters
115
+ while (path[i] && Util::ascii_isalnum(static_cast<unsigned char>(path[i]))) ++i;
116
+ i = i && path[i] == ':' ? i + 1 : 0;
117
+ }
118
+ return path[i] == '/';
119
+ }
120
+
121
+ // helper function to find the last directory separator
122
+ inline size_t find_last_folder_separator(const sass::string& path, size_t limit = sass::string::npos)
123
+ {
124
+ size_t pos;
125
+ size_t pos_p = path.find_last_of('/', limit);
126
+ #ifdef _WIN32
127
+ size_t pos_w = path.find_last_of('\\', limit);
128
+ #else
129
+ size_t pos_w = sass::string::npos;
130
+ #endif
131
+ if (pos_p != sass::string::npos && pos_w != sass::string::npos) {
132
+ pos = std::max(pos_p, pos_w);
133
+ }
134
+ else if (pos_p != sass::string::npos) {
135
+ pos = pos_p;
136
+ }
137
+ else {
138
+ pos = pos_w;
139
+ }
140
+ return pos;
141
+ }
142
+
143
+ // return only the directory part of path
144
+ sass::string dir_name(const sass::string& path)
145
+ {
146
+ size_t pos = find_last_folder_separator(path);
147
+ if (pos == sass::string::npos) return "";
148
+ else return path.substr(0, pos+1);
149
+ }
150
+
151
+ // return only the filename part of path
152
+ sass::string base_name(const sass::string& path)
153
+ {
154
+ size_t pos = find_last_folder_separator(path);
155
+ if (pos == sass::string::npos) return path;
156
+ else return path.substr(pos+1);
157
+ }
158
+
159
+ // do a logical clean up of the path
160
+ // no physical check on the filesystem
161
+ sass::string make_canonical_path (sass::string path)
162
+ {
163
+
164
+ // declarations
165
+ size_t pos;
166
+
167
+ #ifdef _WIN32
168
+ //convert backslashes to forward slashes
169
+ replace(path.begin(), path.end(), '\\', '/');
170
+ #endif
171
+
172
+ pos = 0; // remove all self references inside the path string
173
+ while((pos = path.find("/./", pos)) != sass::string::npos) path.erase(pos, 2);
174
+
175
+ // remove all leading and trailing self references
176
+ while(path.size() >= 2 && path[0] == '.' && path[1] == '/') path.erase(0, 2);
177
+ while((pos = path.length()) > 1 && path[pos - 2] == '/' && path[pos - 1] == '.') path.erase(pos - 2);
178
+
179
+
180
+ size_t proto = 0;
181
+ // check if we have a protocol
182
+ if (path[proto] && Util::ascii_isalpha(static_cast<unsigned char>(path[proto]))) {
183
+ // skip over all alphanumeric characters
184
+ while (path[proto] && Util::ascii_isalnum(static_cast<unsigned char>(path[proto++]))) {}
185
+ // then skip over the mandatory colon
186
+ if (proto && path[proto] == ':') ++ proto;
187
+ }
188
+
189
+ // then skip over start slashes
190
+ while (path[proto++] == '/') {}
191
+
192
+ pos = proto; // collapse multiple delimiters into a single one
193
+ while((pos = path.find("//", pos)) != sass::string::npos) path.erase(pos, 1);
194
+
195
+ return path;
196
+
197
+ }
198
+
199
+ // join two path segments cleanly together
200
+ // but only if right side is not absolute yet
201
+ sass::string join_paths(sass::string l, sass::string r)
202
+ {
203
+
204
+ #ifdef _WIN32
205
+ // convert Windows backslashes to URL forward slashes
206
+ replace(l.begin(), l.end(), '\\', '/');
207
+ replace(r.begin(), r.end(), '\\', '/');
208
+ #endif
209
+
210
+ if (l.empty()) return r;
211
+ if (r.empty()) return l;
212
+
213
+ if (is_absolute_path(r)) return r;
214
+ if (l[l.length()-1] != '/') l += '/';
215
+
216
+ // this does a logical cleanup of the right hand path
217
+ // Note that this does collapse x/../y sections into y.
218
+ // This is by design. If /foo on your system is a symlink
219
+ // to /bar/baz, then /foo/../cd is actually /bar/cd,
220
+ // not /cd as a naive ../ removal would give you.
221
+ // will only work on leading double dot dirs on rhs
222
+ // therefore it is safe if lhs is already resolved cwd
223
+ while ((r.length() > 3) && ((r.substr(0, 3) == "../") || (r.substr(0, 3)) == "..\\")) {
224
+ size_t L = l.length(), pos = find_last_folder_separator(l, L - 2);
225
+ bool is_slash = pos + 2 == L && (l[pos+1] == '/' || l[pos+1] == '\\');
226
+ bool is_self = pos + 3 == L && (l[pos+1] == '.');
227
+ if (!is_self && !is_slash) r = r.substr(3);
228
+ else if (pos == sass::string::npos) break;
229
+ l = l.substr(0, pos == sass::string::npos ? pos : pos + 1);
230
+ }
231
+
232
+ return l + r;
233
+ }
234
+
235
+ sass::string path_for_console(const sass::string& rel_path, const sass::string& abs_path, const sass::string& orig_path)
236
+ {
237
+ // magic algorithm goes here!!
238
+
239
+ // if the file is outside this directory show the absolute path
240
+ if (rel_path.substr(0, 3) == "../") {
241
+ return orig_path;
242
+ }
243
+ // this seems to work most of the time
244
+ return abs_path == orig_path ? abs_path : rel_path;
245
+ }
246
+
247
+ // create an absolute path by resolving relative paths with cwd
248
+ sass::string rel2abs(const sass::string& path, const sass::string& base, const sass::string& cwd)
249
+ {
250
+ sass::string rv = make_canonical_path(join_paths(join_paths(cwd + "/", base + "/"), path));
251
+ #ifdef _WIN32
252
+ // On windows we may get an absolute path without directory
253
+ // In that case we should prepend the directory from the root
254
+ if (rv[0] == '/' && rv[1] != '/') {
255
+ rv.insert(0, cwd, 0, 2);
256
+ }
257
+ #endif
258
+ return rv;
259
+ }
260
+
261
+ // create a path that is relative to the given base directory
262
+ // path and base will first be resolved against cwd to make them absolute
263
+ sass::string abs2rel(const sass::string& path, const sass::string& base, const sass::string& cwd)
264
+ {
265
+
266
+ sass::string abs_path = rel2abs(path, cwd);
267
+ sass::string abs_base = rel2abs(base, cwd);
268
+
269
+ size_t proto = 0;
270
+ // check if we have a protocol
271
+ if (path[proto] && Util::ascii_isalpha(static_cast<unsigned char>(path[proto]))) {
272
+ // skip over all alphanumeric characters
273
+ while (path[proto] && Util::ascii_isalnum(static_cast<unsigned char>(path[proto++]))) {}
274
+ // then skip over the mandatory colon
275
+ if (proto && path[proto] == ':') ++ proto;
276
+ }
277
+
278
+ // distinguish between windows absolute paths and valid protocols
279
+ // we assume that protocols must at least have two chars to be valid
280
+ if (proto && path[proto++] == '/' && proto > 3) return path;
281
+
282
+ #ifdef _WIN32
283
+ // absolute link must have a drive letter, and we know that we
284
+ // can only create relative links if both are on the same drive
285
+ if (abs_base[0] != abs_path[0]) return abs_path;
286
+ #endif
287
+
288
+ sass::string stripped_uri = "";
289
+ sass::string stripped_base = "";
290
+
291
+ size_t index = 0;
292
+ size_t minSize = std::min(abs_path.size(), abs_base.size());
293
+ for (size_t i = 0; i < minSize; ++i) {
294
+ #ifdef FS_CASE_SENSITIVE
295
+ if (abs_path[i] != abs_base[i]) break;
296
+ #else
297
+ // compare the charactes in a case insensitive manner
298
+ // windows fs is only case insensitive in ascii ranges
299
+ if (Util::ascii_tolower(static_cast<unsigned char>(abs_path[i])) !=
300
+ Util::ascii_tolower(static_cast<unsigned char>(abs_base[i]))) break;
301
+ #endif
302
+ if (abs_path[i] == '/') index = i + 1;
303
+ }
304
+ for (size_t i = index; i < abs_path.size(); ++i) {
305
+ stripped_uri += abs_path[i];
306
+ }
307
+ for (size_t i = index; i < abs_base.size(); ++i) {
308
+ stripped_base += abs_base[i];
309
+ }
310
+
311
+ size_t left = 0;
312
+ size_t directories = 0;
313
+ for (size_t right = 0; right < stripped_base.size(); ++right) {
314
+ if (stripped_base[right] == '/') {
315
+ if (stripped_base.substr(left, 2) != "..") {
316
+ ++directories;
317
+ }
318
+ else if (directories > 1) {
319
+ --directories;
320
+ }
321
+ else {
322
+ directories = 0;
323
+ }
324
+ left = right + 1;
325
+ }
326
+ }
327
+
328
+ sass::string result = "";
329
+ for (size_t i = 0; i < directories; ++i) {
330
+ result += "../";
331
+ }
332
+ result += stripped_uri;
333
+
334
+ return result;
335
+ }
336
+
337
+ // Resolution order for ambiguous imports:
338
+ // (1) filename as given
339
+ // (2) underscore + given
340
+ // (3) underscore + given + extension
341
+ // (4) given + extension
342
+ // (5) given + _index.scss
343
+ // (6) given + _index.sass
344
+ sass::vector<Include> resolve_includes(const sass::string& root, const sass::string& file, const sass::vector<sass::string>& exts)
345
+ {
346
+ sass::string filename = join_paths(root, file);
347
+ // split the filename
348
+ sass::string base(dir_name(file));
349
+ sass::string name(base_name(file));
350
+ sass::vector<Include> includes;
351
+ // create full path (maybe relative)
352
+ sass::string rel_path(join_paths(base, name));
353
+ sass::string abs_path(join_paths(root, rel_path));
354
+ if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
355
+ // next test variation with underscore
356
+ rel_path = join_paths(base, "_" + name);
357
+ abs_path = join_paths(root, rel_path);
358
+ if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
359
+ // next test exts plus underscore
360
+ for(auto ext : exts) {
361
+ rel_path = join_paths(base, "_" + name + ext);
362
+ abs_path = join_paths(root, rel_path);
363
+ if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
364
+ }
365
+ // next test plain name with exts
366
+ for(auto ext : exts) {
367
+ rel_path = join_paths(base, name + ext);
368
+ abs_path = join_paths(root, rel_path);
369
+ if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
370
+ }
371
+ // index files
372
+ if (includes.size() == 0) {
373
+ // ignore directories that look like @import'able filename
374
+ for(auto ext : exts) {
375
+ if (ends_with(name, ext)) return includes;
376
+ }
377
+ // next test underscore index exts
378
+ for(auto ext : exts) {
379
+ rel_path = join_paths(base, join_paths(name, "_index" + ext));
380
+ abs_path = join_paths(root, rel_path);
381
+ if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
382
+ }
383
+ // next test plain index exts
384
+ for(auto ext : exts) {
385
+ rel_path = join_paths(base, join_paths(name, "index" + ext));
386
+ abs_path = join_paths(root, rel_path);
387
+ if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
388
+ }
389
+ }
390
+ // nothing found
391
+ return includes;
392
+ }
393
+
394
+ sass::vector<sass::string> find_files(const sass::string& file, const sass::vector<sass::string> paths)
395
+ {
396
+ sass::vector<sass::string> includes;
397
+ for (sass::string path : paths) {
398
+ sass::string abs_path(join_paths(path, file));
399
+ if (file_exists(abs_path)) includes.push_back(abs_path);
400
+ }
401
+ return includes;
402
+ }
403
+
404
+ sass::vector<sass::string> find_files(const sass::string& file, struct Sass_Compiler* compiler)
405
+ {
406
+ // get the last import entry to get current base directory
407
+ // struct Sass_Options* options = sass_compiler_get_options(compiler);
408
+ Sass_Import_Entry import = sass_compiler_get_last_import(compiler);
409
+ const sass::vector<sass::string>& incs = compiler->cpp_ctx->include_paths;
410
+ // create the vector with paths to lookup
411
+ sass::vector<sass::string> paths(1 + incs.size());
412
+ paths.push_back(dir_name(import->abs_path));
413
+ paths.insert(paths.end(), incs.begin(), incs.end());
414
+ // dispatch to find files in paths
415
+ return find_files(file, paths);
416
+ }
417
+
418
+ // helper function to search one file in all include paths
419
+ // this is normally not used internally by libsass (C-API sugar)
420
+ sass::string find_file(const sass::string& file, const sass::vector<sass::string> paths)
421
+ {
422
+ if (file.empty()) return file;
423
+ auto res = find_files(file, paths);
424
+ return res.empty() ? "" : res.front();
425
+ }
426
+
427
+ // helper function to resolve a filename
428
+ sass::string find_include(const sass::string& file, const sass::vector<sass::string> paths)
429
+ {
430
+ // search in every include path for a match
431
+ for (size_t i = 0, S = paths.size(); i < S; ++i)
432
+ {
433
+ sass::vector<Include> resolved(resolve_includes(paths[i], file));
434
+ if (resolved.size()) return resolved[0].abs_path;
435
+ }
436
+ // nothing found
437
+ return sass::string("");
438
+ }
439
+
440
+ // try to load the given filename
441
+ // returned memory must be freed
442
+ // will auto convert .sass files
443
+ char* read_file(const sass::string& path)
444
+ {
445
+ #ifdef _WIN32
446
+ BYTE* pBuffer;
447
+ DWORD dwBytes;
448
+ wchar_t resolved[32768];
449
+ // windows unicode filepaths are encoded in utf16
450
+ sass::string abspath(join_paths(get_cwd(), path));
451
+ if (!(abspath[0] == '/' && abspath[1] == '/')) {
452
+ abspath = "//?/" + abspath;
453
+ }
454
+ std::wstring wpath(UTF_8::convert_to_utf16(abspath));
455
+ std::replace(wpath.begin(), wpath.end(), '/', '\\');
456
+ DWORD rv = GetFullPathNameW(wpath.c_str(), 32767, resolved, NULL);
457
+ if (rv > 32767) throw Exception::OperationError("Path is too long");
458
+ if (rv == 0) throw Exception::OperationError("Path could not be resolved");
459
+ HANDLE hFile = CreateFileW(resolved, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
460
+ if (hFile == INVALID_HANDLE_VALUE) return 0;
461
+ DWORD dwFileLength = GetFileSize(hFile, NULL);
462
+ if (dwFileLength == INVALID_FILE_SIZE) return 0;
463
+ // allocate an extra byte for the null char
464
+ // and another one for edge-cases in lexer
465
+ pBuffer = (BYTE*)malloc((dwFileLength+2)*sizeof(BYTE));
466
+ ReadFile(hFile, pBuffer, dwFileLength, &dwBytes, NULL);
467
+ pBuffer[dwFileLength+0] = '\0';
468
+ pBuffer[dwFileLength+1] = '\0';
469
+ CloseHandle(hFile);
470
+ // just convert from unsigned char*
471
+ char* contents = (char*) pBuffer;
472
+ #else
473
+ // Read the file using `<cstdio>` instead of `<fstream>` for better portability.
474
+ // The `<fstream>` header initializes `<locale>` and this buggy in GCC4/5 with static linking.
475
+ // See:
476
+ // https://www.spinics.net/lists/gcchelp/msg46851.html
477
+ // https://github.com/sass/sassc-ruby/issues/128
478
+ struct stat st;
479
+ if (stat(path.c_str(), &st) == -1 || S_ISDIR(st.st_mode)) return 0;
480
+ FILE* fd = std::fopen(path.c_str(), "rb");
481
+ if (fd == nullptr) return nullptr;
482
+ const std::size_t size = st.st_size;
483
+ char* contents = static_cast<char*>(malloc(st.st_size + 2 * sizeof(char)));
484
+ if (std::fread(static_cast<void*>(contents), 1, size, fd) != size) {
485
+ free(contents);
486
+ std::fclose(fd);
487
+ return nullptr;
488
+ }
489
+ if (std::fclose(fd) != 0) {
490
+ free(contents);
491
+ return nullptr;
492
+ }
493
+ contents[size] = '\0';
494
+ contents[size + 1] = '\0';
495
+ #endif
496
+ sass::string extension;
497
+ if (path.length() > 5) {
498
+ extension = path.substr(path.length() - 5, 5);
499
+ }
500
+ Util::ascii_str_tolower(&extension);
501
+ if (extension == ".sass" && contents != 0) {
502
+ char * converted = sass2scss(contents, SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
503
+ free(contents); // free the indented contents
504
+ return converted; // should be freed by caller
505
+ } else {
506
+ return contents;
507
+ }
508
+ }
509
+
510
+ // split a path string delimited by semicolons or colons (OS dependent)
511
+ sass::vector<sass::string> split_path_list(const char* str)
512
+ {
513
+ sass::vector<sass::string> paths;
514
+ if (str == NULL) return paths;
515
+ // find delimiter via prelexer (return zero at end)
516
+ const char* end = Prelexer::find_first<PATH_SEP>(str);
517
+ // search until null delimiter
518
+ while (end) {
519
+ // add path from current position to delimiter
520
+ paths.push_back(sass::string(str, end - str));
521
+ str = end + 1; // skip delimiter
522
+ end = Prelexer::find_first<PATH_SEP>(str);
523
+ }
524
+ // add path from current position to end
525
+ paths.push_back(sass::string(str));
526
+ // return back
527
+ return paths;
528
+ }
529
+
530
+ }
531
+ }
@@ -0,0 +1,124 @@
1
+ #ifndef SASS_FILE_H
2
+ #define SASS_FILE_H
3
+
4
+ // sass.hpp must go before all system headers to get the
5
+ // __EXTENSIONS__ fix on Solaris.
6
+ #include "sass.hpp"
7
+
8
+ #include <string>
9
+ #include <vector>
10
+
11
+ #include "sass/context.h"
12
+ #include "ast_fwd_decl.hpp"
13
+
14
+ namespace Sass {
15
+
16
+ namespace File {
17
+
18
+ // return the current directory
19
+ // always with forward slashes
20
+ sass::string get_cwd();
21
+
22
+ // test if path exists and is a file
23
+ bool file_exists(const sass::string& file);
24
+
25
+ // return if given path is absolute
26
+ // works with *nix and windows paths
27
+ bool is_absolute_path(const sass::string& path);
28
+
29
+ // return only the directory part of path
30
+ sass::string dir_name(const sass::string& path);
31
+
32
+ // return only the filename part of path
33
+ sass::string base_name(const sass::string&);
34
+
35
+ // do a locigal clean up of the path
36
+ // no physical check on the filesystem
37
+ sass::string make_canonical_path (sass::string path);
38
+
39
+ // join two path segments cleanly together
40
+ // but only if right side is not absolute yet
41
+ sass::string join_paths(sass::string root, sass::string name);
42
+
43
+ // if the relative path is outside of the cwd we want want to
44
+ // show the absolute path in console messages
45
+ sass::string path_for_console(const sass::string& rel_path, const sass::string& abs_path, const sass::string& orig_path);
46
+
47
+ // create an absolute path by resolving relative paths with cwd
48
+ sass::string rel2abs(const sass::string& path, const sass::string& base = ".", const sass::string& cwd = get_cwd());
49
+
50
+ // create a path that is relative to the given base directory
51
+ // path and base will first be resolved against cwd to make them absolute
52
+ sass::string abs2rel(const sass::string& path, const sass::string& base = ".", const sass::string& cwd = get_cwd());
53
+
54
+ // helper function to resolve a filename
55
+ // searching without variations in all paths
56
+ sass::string find_file(const sass::string& file, struct Sass_Compiler* options);
57
+ sass::string find_file(const sass::string& file, const sass::vector<sass::string> paths);
58
+
59
+ // helper function to resolve a include filename
60
+ // this has the original resolve logic for sass include
61
+ sass::string find_include(const sass::string& file, const sass::vector<sass::string> paths);
62
+
63
+ // split a path string delimited by semicolons or colons (OS dependent)
64
+ sass::vector<sass::string> split_path_list(const char* paths);
65
+
66
+ // try to load the given filename
67
+ // returned memory must be freed
68
+ // will auto convert .sass files
69
+ char* read_file(const sass::string& file);
70
+
71
+ }
72
+
73
+ // requested import
74
+ class Importer {
75
+ public:
76
+ // requested import path
77
+ sass::string imp_path;
78
+ // parent context path
79
+ sass::string ctx_path;
80
+ // base derived from context path
81
+ // this really just acts as a cache
82
+ sass::string base_path;
83
+ public:
84
+ Importer(sass::string imp_path, sass::string ctx_path)
85
+ : imp_path(File::make_canonical_path(imp_path)),
86
+ ctx_path(File::make_canonical_path(ctx_path)),
87
+ base_path(File::dir_name(ctx_path))
88
+ { }
89
+ };
90
+
91
+ // a resolved include (final import)
92
+ class Include : public Importer {
93
+ public:
94
+ // resolved absolute path
95
+ sass::string abs_path;
96
+ public:
97
+ Include(const Importer& imp, sass::string abs_path)
98
+ : Importer(imp), abs_path(abs_path)
99
+ { }
100
+ };
101
+
102
+ // a loaded resource
103
+ class Resource {
104
+ public:
105
+ // the file contents
106
+ char* contents;
107
+ // connected sourcemap
108
+ char* srcmap;
109
+ public:
110
+ Resource(char* contents, char* srcmap)
111
+ : contents(contents), srcmap(srcmap)
112
+ { }
113
+ };
114
+
115
+ namespace File {
116
+
117
+ sass::vector<Include> resolve_includes(const sass::string& root, const sass::string& file,
118
+ const sass::vector<sass::string>& exts = { ".scss", ".sass", ".css" });
119
+
120
+ }
121
+
122
+ }
123
+
124
+ #endif