1 | // sass.hpp must go before all system headers to get the |
2 | // __EXTENSIONS__ fix on Solaris. |
3 | #include "sass.hpp" |
4 | |
5 | #include <cstdlib> |
6 | #include <cstring> |
7 | #include <vector> |
8 | #include <sstream> |
9 | |
10 | #include "sass.h" |
11 | #include "file.hpp" |
12 | #include "util.hpp" |
13 | #include "context.hpp" |
14 | #include "sass_context.hpp" |
15 | #include "sass_functions.hpp" |
16 | |
17 | namespace Sass { |
18 | |
19 | // helper to convert string list to vector |
20 | sass::vector<sass::string> list2vec(struct string_list* cur) |
21 | { |
22 | sass::vector<sass::string> list; |
23 | while (cur) { |
24 | list.push_back(x: cur->string); |
25 | cur = cur->next; |
26 | } |
27 | return list; |
28 | } |
29 | |
30 | } |
31 | |
32 | extern "C" { |
33 | using namespace Sass; |
34 | |
35 | // Allocate libsass heap memory |
36 | // Don't forget string termination! |
37 | void* ADDCALL sass_alloc_memory(size_t size) |
38 | { |
39 | void* ptr = malloc(size: size); |
40 | if (ptr == NULL) { |
41 | std::cerr << "Out of memory.\n" ; |
42 | exit(EXIT_FAILURE); |
43 | } |
44 | return ptr; |
45 | } |
46 | |
47 | char* ADDCALL sass_copy_c_string(const char* str) |
48 | { |
49 | if (str == nullptr) return nullptr; |
50 | size_t len = strlen(s: str) + 1; |
51 | char* cpy = (char*) sass_alloc_memory(size: len); |
52 | std::memcpy(dest: cpy, src: str, n: len); |
53 | return cpy; |
54 | } |
55 | |
56 | // Deallocate libsass heap memory |
57 | void ADDCALL sass_free_memory(void* ptr) |
58 | { |
59 | if (ptr) free (ptr: ptr); |
60 | } |
61 | |
62 | // caller must free the returned memory |
63 | char* ADDCALL sass_string_quote (const char *str, const char quote_mark) |
64 | { |
65 | sass::string quoted = quote(str, q: quote_mark); |
66 | return sass_copy_c_string(str: quoted.c_str()); |
67 | } |
68 | |
69 | // caller must free the returned memory |
70 | char* ADDCALL sass_string_unquote (const char *str) |
71 | { |
72 | sass::string unquoted = unquote(str); |
73 | return sass_copy_c_string(str: unquoted.c_str()); |
74 | } |
75 | |
76 | char* ADDCALL sass_compiler_find_include (const char* file, struct Sass_Compiler* compiler) |
77 | { |
78 | // get the last import entry to get current base directory |
79 | Sass_Import_Entry import = sass_compiler_get_last_import(compiler); |
80 | const sass::vector<sass::string>& incs = compiler->cpp_ctx->include_paths; |
81 | // create the vector with paths to lookup |
82 | sass::vector<sass::string> paths(1 + incs.size()); |
83 | paths.push_back(x: File::dir_name(path: import->abs_path)); |
84 | paths.insert( position: paths.end(), first: incs.begin(), last: incs.end() ); |
85 | // now resolve the file path relative to lookup paths |
86 | sass::string resolved(File::find_include(file, paths)); |
87 | return sass_copy_c_string(str: resolved.c_str()); |
88 | } |
89 | |
90 | char* ADDCALL sass_compiler_find_file (const char* file, struct Sass_Compiler* compiler) |
91 | { |
92 | // get the last import entry to get current base directory |
93 | Sass_Import_Entry import = sass_compiler_get_last_import(compiler); |
94 | const sass::vector<sass::string>& incs = compiler->cpp_ctx->include_paths; |
95 | // create the vector with paths to lookup |
96 | sass::vector<sass::string> paths(1 + incs.size()); |
97 | paths.push_back(x: File::dir_name(path: import->abs_path)); |
98 | paths.insert( position: paths.end(), first: incs.begin(), last: incs.end() ); |
99 | // now resolve the file path relative to lookup paths |
100 | sass::string resolved(File::find_file(file, paths)); |
101 | return sass_copy_c_string(str: resolved.c_str()); |
102 | } |
103 | |
104 | // Make sure to free the returned value! |
105 | // Incs array has to be null terminated! |
106 | // this has the original resolve logic for sass include |
107 | char* ADDCALL sass_find_include (const char* file, struct Sass_Options* opt) |
108 | { |
109 | sass::vector<sass::string> vec(list2vec(cur: opt->include_paths)); |
110 | sass::string resolved(File::find_include(file, paths: vec)); |
111 | return sass_copy_c_string(str: resolved.c_str()); |
112 | } |
113 | |
114 | // Make sure to free the returned value! |
115 | // Incs array has to be null terminated! |
116 | char* ADDCALL sass_find_file (const char* file, struct Sass_Options* opt) |
117 | { |
118 | sass::vector<sass::string> vec(list2vec(cur: opt->include_paths)); |
119 | sass::string resolved(File::find_file(file, paths: vec)); |
120 | return sass_copy_c_string(str: resolved.c_str()); |
121 | } |
122 | |
123 | // Get compiled libsass version |
124 | const char* ADDCALL libsass_version(void) |
125 | { |
126 | return LIBSASS_VERSION; |
127 | } |
128 | |
129 | // Get compiled libsass version |
130 | const char* ADDCALL libsass_language_version(void) |
131 | { |
132 | return LIBSASS_LANGUAGE_VERSION; |
133 | } |
134 | |
135 | } |
136 | |
137 | namespace Sass { |
138 | |
139 | // helper to aid dreaded MSVC debug mode |
140 | char* sass_copy_string(sass::string str) |
141 | { |
142 | // In MSVC the following can lead to segfault: |
143 | // sass_copy_c_string(stream.str().c_str()); |
144 | // Reason is that the string returned by str() is disposed before |
145 | // sass_copy_c_string is invoked. The string is actually a stack |
146 | // object, so indeed nobody is holding on to it. So it seems |
147 | // perfectly fair to release it right away. So the const char* |
148 | // by c_str will point to invalid memory. I'm not sure if this is |
149 | // the behavior for all compiler, but I'm pretty sure we would |
150 | // have gotten more issues reported if that would be the case. |
151 | // Wrapping it in a functions seems the cleanest approach as the |
152 | // function must hold on to the stack variable until it's done. |
153 | return sass_copy_c_string(str: str.c_str()); |
154 | } |
155 | |
156 | } |
157 | |