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
17namespace 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
32extern "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
137namespace 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

source code of gtk/subprojects/libsass/src/sass.cpp