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