Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / context.cpp
1 #include "sass.hpp"
2 #include <string>
3 #include <cstdlib>
4 #include <cstring>
5 #include <iomanip>
6 #include <sstream>
7 #include <iostream>
8
9 #include "ast.hpp"
10 #include "util.hpp"
11 #include "sass.h"
12 #include "context.hpp"
13 #include "plugins.hpp"
14 #include "constants.hpp"
15 #include "parser.hpp"
16 #include "file.hpp"
17 #include "inspect.hpp"
18 #include "output.hpp"
19 #include "expand.hpp"
20 #include "eval.hpp"
21 #include "check_nesting.hpp"
22 #include "cssize.hpp"
23 #include "listize.hpp"
24 #include "extend.hpp"
25 #include "remove_placeholders.hpp"
26 #include "functions.hpp"
27 #include "sass_functions.hpp"
28 #include "backtrace.hpp"
29 #include "sass2scss.h"
30 #include "prelexer.hpp"
31 #include "emitter.hpp"
32
33 namespace Sass {
34   using namespace Constants;
35   using namespace File;
36   using namespace Sass;
37
38   inline bool sort_importers (const Sass_Importer_Entry& i, const Sass_Importer_Entry& j)
39   { return sass_importer_get_priority(i) > sass_importer_get_priority(j); }
40
41   static std::string safe_input(const char* in_path)
42   {
43     // enforce some safe defaults
44     // used to create relative file links
45     std::string safe_path(in_path ? in_path : "");
46     return safe_path == "" ? "stdin" : safe_path;
47   }
48
49   static std::string safe_output(const char* out_path, const std::string& input_path = "")
50   {
51     std::string safe_path(out_path ? out_path : "");
52     // maybe we can extract an output path from input path
53     if (safe_path == "" && input_path != "") {
54       int lastindex = static_cast<int>(input_path.find_last_of("."));
55       return (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
56     }
57     // enforce some safe defaults
58     // used to create relative file links
59     return safe_path == "" ? "stdout" : safe_path;
60   }
61
62   Context::Context(struct Sass_Context& c_ctx)
63   : CWD(File::get_cwd()),
64     c_options(c_ctx),
65     entry_path(""),
66     head_imports(0),
67     plugins(),
68     emitter(c_options),
69
70     strings(),
71     resources(),
72     sheets(),
73     subset_map(),
74     import_stack(),
75
76     c_headers               (std::vector<Sass_Importer_Entry>()),
77     c_importers             (std::vector<Sass_Importer_Entry>()),
78     c_functions             (std::vector<Sass_Function_Entry>()),
79
80     indent                  (safe_str(c_options.indent, "  ")),
81     linefeed                (safe_str(c_options.linefeed, "\n")),
82
83     input_path              (make_canonical_path(safe_input(c_options.input_path))),
84     output_path             (make_canonical_path(safe_output(c_options.output_path, input_path))),
85     source_map_file         (make_canonical_path(safe_str(c_options.source_map_file, ""))),
86     source_map_root         (make_canonical_path(safe_str(c_options.source_map_root, "")))
87
88   {
89
90     // Sass 3.4: The current working directory will no longer be placed onto the Sass load path by default.
91     // If you need the current working directory to be available, set SASS_PATH=. in your shell's environment.
92     // include_paths.push_back(CWD);
93
94     // collect more paths from different options
95     collect_include_paths(c_options.include_path);
96     collect_include_paths(c_options.include_paths);
97     collect_plugin_paths(c_options.plugin_path);
98     collect_plugin_paths(c_options.plugin_paths);
99
100     // load plugins and register custom behaviors
101     for(auto plug : plugin_paths) plugins.load_plugins(plug);
102     for(auto fn : plugins.get_headers()) c_headers.push_back(fn);
103     for(auto fn : plugins.get_importers()) c_importers.push_back(fn);
104     for(auto fn : plugins.get_functions()) c_functions.push_back(fn);
105
106     // sort the items by priority (lowest first)
107     sort (c_headers.begin(), c_headers.end(), sort_importers);
108     sort (c_importers.begin(), c_importers.end(), sort_importers);
109
110     emitter.set_filename(abs2rel(output_path, source_map_file, CWD));
111
112   }
113
114   void Context::add_c_function(Sass_Function_Entry function)
115   {
116     c_functions.push_back(function);
117   }
118   void Context::add_c_header(Sass_Importer_Entry header)
119   {
120     c_headers.push_back(header);
121     // need to sort the array afterwards (no big deal)
122     sort (c_headers.begin(), c_headers.end(), sort_importers);
123   }
124   void Context::add_c_importer(Sass_Importer_Entry importer)
125   {
126     c_importers.push_back(importer);
127     // need to sort the array afterwards (no big deal)
128     sort (c_importers.begin(), c_importers.end(), sort_importers);
129   }
130
131   Context::~Context()
132   {
133     // resources were allocated by strdup or malloc
134     for (size_t i = 0; i < resources.size(); ++i) {
135       free(resources[i].contents);
136       free(resources[i].srcmap);
137     }
138     // free all strings we kept alive during compiler execution
139     for (size_t n = 0; n < strings.size(); ++n) free(strings[n]);
140     // everything that gets put into sources will be freed by us
141     // this shouldn't have anything in it anyway!?
142     for (size_t m = 0; m < import_stack.size(); ++m) {
143       sass_import_take_source(import_stack[m]);
144       sass_import_take_srcmap(import_stack[m]);
145       sass_delete_import(import_stack[m]);
146     }
147     // clear inner structures (vectors) and input source
148     resources.clear(); import_stack.clear();
149     subset_map.clear(), sheets.clear();
150   }
151
152   Data_Context::~Data_Context()
153   {
154     // --> this will be freed by resources
155     // make sure we free the source even if not processed!
156     // if (resources.size() == 0 && source_c_str) free(source_c_str);
157     // if (resources.size() == 0 && srcmap_c_str) free(srcmap_c_str);
158     // source_c_str = 0; srcmap_c_str = 0;
159   }
160
161   File_Context::~File_Context()
162   {
163   }
164
165   void Context::collect_include_paths(const char* paths_str)
166   {
167     if (paths_str) {
168       const char* beg = paths_str;
169       const char* end = Prelexer::find_first<PATH_SEP>(beg);
170
171       while (end) {
172         std::string path(beg, end - beg);
173         if (!path.empty()) {
174           if (*path.rbegin() != '/') path += '/';
175           include_paths.push_back(path);
176         }
177         beg = end + 1;
178         end = Prelexer::find_first<PATH_SEP>(beg);
179       }
180
181       std::string path(beg);
182       if (!path.empty()) {
183         if (*path.rbegin() != '/') path += '/';
184         include_paths.push_back(path);
185       }
186     }
187   }
188
189   void Context::collect_include_paths(string_list* paths_array)
190   {
191     while (paths_array)
192     {
193       collect_include_paths(paths_array->string);
194       paths_array = paths_array->next;
195     }
196   }
197
198   void Context::collect_plugin_paths(const char* paths_str)
199   {
200     if (paths_str) {
201       const char* beg = paths_str;
202       const char* end = Prelexer::find_first<PATH_SEP>(beg);
203
204       while (end) {
205         std::string path(beg, end - beg);
206         if (!path.empty()) {
207           if (*path.rbegin() != '/') path += '/';
208           plugin_paths.push_back(path);
209         }
210         beg = end + 1;
211         end = Prelexer::find_first<PATH_SEP>(beg);
212       }
213
214       std::string path(beg);
215       if (!path.empty()) {
216         if (*path.rbegin() != '/') path += '/';
217         plugin_paths.push_back(path);
218       }
219     }
220   }
221
222   void Context::collect_plugin_paths(string_list* paths_array)
223   {
224     while (paths_array)
225     {
226       collect_plugin_paths(paths_array->string);
227       paths_array = paths_array->next;
228     }
229   }
230
231   // resolve the imp_path in base_path or include_paths
232   // looks for alternatives and returns a list from one directory
233   std::vector<Include> Context::find_includes(const Importer& import)
234   {
235     // make sure we resolve against an absolute path
236     std::string base_path(rel2abs(import.base_path));
237     // first try to resolve the load path relative to the base path
238     std::vector<Include> vec(resolve_includes(base_path, import.imp_path));
239     // then search in every include path (but only if nothing found yet)
240     for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i)
241     {
242       // call resolve_includes and individual base path and append all results
243       std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path));
244       if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end());
245     }
246     // return vector
247     return vec;
248   }
249
250
251   // register include with resolved path and its content
252   // memory of the resources will be freed by us on exit
253   void Context::register_resource(const Include& inc, const Resource& res, ParserState* prstate)
254   {
255
256     // do not parse same resource twice
257     // maybe raise an error in this case
258     // if (sheets.count(inc.abs_path)) {
259     //   free(res.contents); free(res.srcmap);
260     //   throw std::runtime_error("duplicate resource registered");
261     //   return;
262     // }
263
264     // get index for this resource
265     size_t idx = resources.size();
266
267     // tell emitter about new resource
268     emitter.add_source_index(idx);
269
270     // put resources under our control
271     // the memory will be freed later
272     resources.push_back(res);
273
274     // add a relative link to the working directory
275     included_files.push_back(inc.abs_path);
276     // add a relative link  to the source map output file
277     srcmap_links.push_back(abs2rel(inc.abs_path, source_map_file, CWD));
278
279     // get pointer to the loaded content
280     Sass_Import_Entry import = sass_make_import(
281       inc.imp_path.c_str(),
282       inc.abs_path.c_str(),
283       res.contents,
284       res.srcmap
285     );
286     // add the entry to the stack
287     import_stack.push_back(import);
288
289     // get pointer to the loaded content
290     const char* contents = resources[idx].contents;
291     // keep a copy of the path around (for parserstates)
292     // ToDo: we clean it, but still not very elegant!?
293     strings.push_back(sass_copy_c_string(inc.abs_path.c_str()));
294     // create the initial parser state from resource
295     ParserState pstate(strings.back(), contents, idx);
296
297     // check existing import stack for possible recursion
298     for (size_t i = 0; i < import_stack.size() - 2; ++i) {
299       auto parent = import_stack[i];
300       if (std::strcmp(parent->abs_path, import->abs_path) == 0) {
301         std::string stack("An @import loop has been found:");
302         for (size_t n = 1; n < i + 2; ++n) {
303           stack += "\n    " + std::string(import_stack[n]->imp_path) +
304             " imports " + std::string(import_stack[n+1]->imp_path);
305         }
306         // implement error throw directly until we
307         // decided how to handle full stack traces
308         ParserState state = prstate ? *prstate : pstate;
309         throw Exception::InvalidSyntax(state, stack, &import_stack);
310         // error(stack, prstate ? *prstate : pstate, import_stack);
311       }
312     }
313
314     // create a parser instance from the given c_str buffer
315     Parser p(Parser::from_c_str(contents, *this, pstate));
316     // do not yet dispose these buffers
317     sass_import_take_source(import);
318     sass_import_take_srcmap(import);
319     // then parse the root block
320     Block_Obj root = p.parse();
321     // delete memory of current stack frame
322     sass_delete_import(import_stack.back());
323     // remove current stack frame
324     import_stack.pop_back();
325     // create key/value pair for ast node
326     std::pair<const std::string, StyleSheet>
327       ast_pair(inc.abs_path, { res, root });
328     // register resulting resource
329     sheets.insert(ast_pair);
330
331   }
332
333   // Add a new import to the context (called from `import_url`)
334   Include Context::load_import(const Importer& imp, ParserState pstate)
335   {
336
337     // search for valid imports (ie. partials) on the filesystem
338     // this may return more than one valid result (ambiguous imp_path)
339     const std::vector<Include> resolved(find_includes(imp));
340
341     // error nicely on ambiguous imp_path
342     if (resolved.size() > 1) {
343       std::stringstream msg_stream;
344       msg_stream << "It's not clear which file to import for ";
345       msg_stream << "'@import \"" << imp.imp_path << "\"'." << "\n";
346       msg_stream << "Candidates:" << "\n";
347       for (size_t i = 0, L = resolved.size(); i < L; ++i)
348       { msg_stream << "  " << resolved[i].imp_path << "\n"; }
349       msg_stream << "Please delete or rename all but one of these files." << "\n";
350       error(msg_stream.str(), pstate);
351     }
352
353     // process the resolved entry
354     else if (resolved.size() == 1) {
355       bool use_cache = c_importers.size() == 0;
356       // use cache for the resource loading
357       if (use_cache && sheets.count(resolved[0].abs_path)) return resolved[0];
358       // try to read the content of the resolved file entry
359       // the memory buffer returned must be freed by us!
360       if (char* contents = read_file(resolved[0].abs_path)) {
361         // register the newly resolved file resource
362         register_resource(resolved[0], { contents, 0 }, &pstate);
363         // return resolved entry
364         return resolved[0];
365       }
366     }
367
368     // nothing found
369     return { imp, "" };
370
371   }
372
373   void Context::import_url (Import_Ptr imp, std::string load_path, const std::string& ctx_path) {
374
375     ParserState pstate(imp->pstate());
376     std::string imp_path(unquote(load_path));
377     std::string protocol("file");
378
379     using namespace Prelexer;
380     if (const char* proto = sequence< identifier, exactly<':'>, exactly<'/'>, exactly<'/'> >(imp_path.c_str())) {
381
382       protocol = std::string(imp_path.c_str(), proto - 3);
383       // if (protocol.compare("file") && true) { }
384     }
385
386     // add urls (protocol other than file) and urls without procotol to `urls` member
387     // ToDo: if ctx_path is already a file resource, we should not add it here?
388     if (imp->import_queries() || protocol != "file" || imp_path.substr(0, 2) == "//") {
389       imp->urls().push_back(SASS_MEMORY_NEW(String_Quoted, imp->pstate(), load_path));
390     }
391     else if (imp_path.length() > 4 && imp_path.substr(imp_path.length() - 4, 4) == ".css") {
392       String_Constant_Ptr loc = SASS_MEMORY_NEW(String_Constant, pstate, unquote(load_path));
393       Argument_Obj loc_arg = SASS_MEMORY_NEW(Argument, pstate, loc);
394       Arguments_Obj loc_args = SASS_MEMORY_NEW(Arguments, pstate);
395       loc_args->append(loc_arg);
396       Function_Call_Ptr new_url = SASS_MEMORY_NEW(Function_Call, pstate, "url", loc_args);
397       imp->urls().push_back(new_url);
398     }
399     else {
400       const Importer importer(imp_path, ctx_path);
401       Include include(load_import(importer, pstate));
402       if (include.abs_path.empty()) {
403         error("File to import not found or unreadable: " + imp_path + ".\nParent style sheet: " + ctx_path, pstate);
404       }
405       imp->incs().push_back(include);
406     }
407
408   }
409
410
411   // call custom importers on the given (unquoted) load_path and eventually parse the resulting style_sheet
412   bool Context::call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import_Ptr imp, std::vector<Sass_Importer_Entry> importers, bool only_one)
413   {
414     // unique counter
415     size_t count = 0;
416     // need one correct import
417     bool has_import = false;
418     // process all custom importers (or custom headers)
419     for (Sass_Importer_Entry& importer : importers) {
420       // int priority = sass_importer_get_priority(importer);
421       Sass_Importer_Fn fn = sass_importer_get_function(importer);
422       // skip importer if it returns NULL
423       if (Sass_Import_List includes =
424           fn(load_path.c_str(), importer, c_compiler)
425       ) {
426         // get c pointer copy to iterate over
427         Sass_Import_List it_includes = includes;
428         while (*it_includes) { ++count;
429           // create unique path to use as key
430           std::string uniq_path = load_path;
431           if (!only_one && count) {
432             std::stringstream path_strm;
433             path_strm << uniq_path << ":" << count;
434             uniq_path = path_strm.str();
435           }
436           // create the importer struct
437           Importer importer(uniq_path, ctx_path);
438           // query data from the current include
439           Sass_Import_Entry include = *it_includes;
440           char* source = sass_import_take_source(include);
441           char* srcmap = sass_import_take_srcmap(include);
442           size_t line = sass_import_get_error_line(include);
443           size_t column = sass_import_get_error_column(include);
444           const char *abs_path = sass_import_get_abs_path(include);
445           // handle error message passed back from custom importer
446           // it may (or may not) override the line and column info
447           if (const char* err_message = sass_import_get_error_message(include)) {
448             if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap }, &pstate);
449             if (line == std::string::npos && column == std::string::npos) error(err_message, pstate);
450             else error(err_message, ParserState(ctx_path, source, Position(line, column)));
451           }
452           // content for import was set
453           else if (source) {
454             // resolved abs_path should be set by custom importer
455             // use the created uniq_path as fallback (maybe enforce)
456             std::string path_key(abs_path ? abs_path : uniq_path);
457             // create the importer struct
458             Include include(importer, path_key);
459             // attach information to AST node
460             imp->incs().push_back(include);
461             // register the resource buffers
462             register_resource(include, { source, srcmap }, &pstate);
463           }
464           // only a path was retuned
465           // try to load it like normal
466           else if(abs_path) {
467             // checks some urls to preserve
468             // `http://`, `https://` and `//`
469             // or dispatchs to `import_file`
470             // which will check for a `.css` extension
471             // or resolves the file on the filesystem
472             // added and resolved via `add_file`
473             // finally stores everything on `imp`
474             import_url(imp, abs_path, ctx_path);
475           }
476           // move to next
477           ++it_includes;
478         }
479         // deallocate the returned memory
480         sass_delete_import_list(includes);
481         // set success flag
482         has_import = true;
483         // break out of loop
484         if (only_one) break;
485       }
486     }
487     // return result
488     return has_import;
489   }
490
491   void register_function(Context&, Signature sig, Native_Function f, Env* env);
492   void register_function(Context&, Signature sig, Native_Function f, size_t arity, Env* env);
493   void register_overload_stub(Context&, std::string name, Env* env);
494   void register_built_in_functions(Context&, Env* env);
495   void register_c_functions(Context&, Env* env, Sass_Function_List);
496   void register_c_function(Context&, Env* env, Sass_Function_Entry);
497
498   char* Context::render(Block_Obj root)
499   {
500     // check for valid block
501     if (!root) return 0;
502     // start the render process
503     root->perform(&emitter);
504     // finish emitter stream
505     emitter.finalize();
506     // get the resulting buffer from stream
507     OutputBuffer emitted = emitter.get_buffer();
508     // should we append a source map url?
509     if (!c_options.omit_source_map_url) {
510       // generate an embeded source map
511       if (c_options.source_map_embed) {
512         emitted.buffer += linefeed;
513         emitted.buffer += format_embedded_source_map();
514       }
515       // or just link the generated one
516       else if (source_map_file != "") {
517         emitted.buffer += linefeed;
518         emitted.buffer += format_source_mapping_url(source_map_file);
519       }
520     }
521     // create a copy of the resulting buffer string
522     // this must be freed or taken over by implementor
523     return sass_copy_c_string(emitted.buffer.c_str());
524   }
525
526   void Context::apply_custom_headers(Block_Obj root, const char* ctx_path, ParserState pstate)
527   {
528     // create a custom import to resolve headers
529     Import_Obj imp = SASS_MEMORY_NEW(Import, pstate);
530     // dispatch headers which will add custom functions
531     // custom headers are added to the import instance
532     call_headers(entry_path, ctx_path, pstate, imp);
533     // increase head count to skip later
534     head_imports += resources.size() - 1;
535     // add the statement if we have urls
536     if (!imp->urls().empty()) root->append(imp);
537     // process all other resources (add Import_Stub nodes)
538     for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
539       root->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
540     }
541   }
542
543   Block_Obj File_Context::parse()
544   {
545
546     // check if entry file is given
547     if (input_path.empty()) return 0;
548
549     // create absolute path from input filename
550     // ToDo: this should be resolved via custom importers
551     std::string abs_path(rel2abs(input_path, CWD));
552
553     // try to load the entry file
554     char* contents = read_file(abs_path);
555
556     // alternatively also look inside each include path folder
557     // I think this differs from ruby sass (IMO too late to remove)
558     for (size_t i = 0, S = include_paths.size(); contents == 0 && i < S; ++i) {
559       // build absolute path for this include path entry
560       abs_path = rel2abs(input_path, include_paths[i]);
561       // try to load the resulting path
562       contents = read_file(abs_path);
563     }
564
565     // abort early if no content could be loaded (various reasons)
566     if (!contents) throw std::runtime_error("File to read not found or unreadable: " + input_path);
567
568     // store entry path
569     entry_path = abs_path;
570
571     // create entry only for import stack
572     Sass_Import_Entry import = sass_make_import(
573       input_path.c_str(),
574       entry_path.c_str(),
575       contents,
576       0
577     );
578     // add the entry to the stack
579     import_stack.push_back(import);
580
581     // create the source entry for file entry
582     register_resource({{ input_path, "." }, abs_path }, { contents, 0 });
583
584     // create root ast tree node
585     return compile();
586
587   }
588
589   Block_Obj Data_Context::parse()
590   {
591
592     // check if source string is given
593     if (!source_c_str) return 0;
594
595     // convert indented sass syntax
596     if(c_options.is_indented_syntax_src) {
597       // call sass2scss to convert the string
598       char * converted = sass2scss(source_c_str,
599         // preserve the structure as much as possible
600         SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
601       // replace old source_c_str with converted
602       free(source_c_str); source_c_str = converted;
603     }
604
605     // remember entry path (defaults to stdin for string)
606     entry_path = input_path.empty() ? "stdin" : input_path;
607
608     // ToDo: this may be resolved via custom importers
609     std::string abs_path(rel2abs(entry_path));
610     char* abs_path_c_str = sass_copy_c_string(abs_path.c_str());
611     strings.push_back(abs_path_c_str);
612
613     // create entry only for the import stack
614     Sass_Import_Entry import = sass_make_import(
615       entry_path.c_str(),
616       abs_path_c_str,
617       source_c_str,
618       srcmap_c_str
619     );
620     // add the entry to the stack
621     import_stack.push_back(import);
622
623     // register a synthetic resource (path does not really exist, skip in includes)
624     register_resource({{ input_path, "." }, input_path }, { source_c_str, srcmap_c_str });
625
626     // create root ast tree node
627     return compile();
628   }
629
630
631
632   // parse root block from includes
633   Block_Obj Context::compile()
634   {
635     // abort if there is no data
636     if (resources.size() == 0) return 0;
637     // get root block from the first style sheet
638     Block_Obj root = sheets.at(entry_path).root;
639     // abort on invalid root
640     if (root.isNull()) return 0;
641     Env global; // create root environment
642     // register built-in functions on env
643     register_built_in_functions(*this, &global);
644     // register custom functions (defined via C-API)
645     for (size_t i = 0, S = c_functions.size(); i < S; ++i)
646     { register_c_function(*this, &global, c_functions[i]); }
647     // create initial backtrace entry
648     Backtrace backtrace(0, ParserState("", 0), "");
649     // create crtp visitor objects
650     Expand expand(*this, &global, &backtrace);
651     Cssize cssize(*this, &backtrace);
652     CheckNesting check_nesting;
653     // check nesting
654     check_nesting(root);
655     // expand and eval the tree
656     root = expand(root);
657     // check nesting
658     check_nesting(root);
659     // merge and bubble certain rules
660     root = cssize(root);
661     // should we extend something?
662     if (!subset_map.empty()) {
663       // create crtp visitor object
664       Extend extend(*this, subset_map);
665       // extend tree nodes
666       extend(root);
667     }
668
669     // clean up by removing empty placeholders
670     // ToDo: maybe we can do this somewhere else?
671     Remove_Placeholders remove_placeholders;
672     root->perform(&remove_placeholders);
673     // return processed tree
674     return root;
675   }
676   // EO compile
677
678   std::string Context::format_embedded_source_map()
679   {
680     std::string map = emitter.render_srcmap(*this);
681     std::istringstream is( map );
682     std::ostringstream buffer;
683     base64::encoder E;
684     E.encode(is, buffer);
685     std::string url = "data:application/json;base64," + buffer.str();
686     url.erase(url.size() - 1);
687     return "/*# sourceMappingURL=" + url + " */";
688   }
689
690   std::string Context::format_source_mapping_url(const std::string& file)
691   {
692     std::string url = abs2rel(file, output_path, CWD);
693     return "/*# sourceMappingURL=" + url + " */";
694   }
695
696   char* Context::render_srcmap()
697   {
698     if (source_map_file == "") return 0;
699     char* result = 0;
700     std::string map = emitter.render_srcmap(*this);
701     result = sass_copy_c_string(map.c_str());
702     return result;
703   }
704
705
706   // for data context we want to start after "stdin"
707   // we probably always want to skip the header includes?
708   std::vector<std::string> Context::get_included_files(bool skip, size_t headers)
709   {
710       // create a copy of the vector for manipulations
711       std::vector<std::string> includes = included_files;
712       if (includes.size() == 0) return includes;
713       if (skip) { includes.erase( includes.begin(), includes.begin() + 1 + headers); }
714       else { includes.erase( includes.begin() + 1, includes.begin() + 1 + headers); }
715       includes.erase( std::unique( includes.begin(), includes.end() ), includes.end() );
716       std::sort( includes.begin() + (skip ? 0 : 1), includes.end() );
717       return includes;
718   }
719
720   void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
721   {
722     Definition_Ptr def = make_native_function(sig, f, ctx);
723     def->environment(env);
724     (*env)[def->name() + "[f]"] = def;
725   }
726
727   void register_function(Context& ctx, Signature sig, Native_Function f, size_t arity, Env* env)
728   {
729     Definition_Ptr def = make_native_function(sig, f, ctx);
730     std::stringstream ss;
731     ss << def->name() << "[f]" << arity;
732     def->environment(env);
733     (*env)[ss.str()] = def;
734   }
735
736   void register_overload_stub(Context& ctx, std::string name, Env* env)
737   {
738     Definition_Ptr stub = SASS_MEMORY_NEW(Definition,
739                                        ParserState("[built-in function]"),
740                                        0,
741                                        name,
742                                        0,
743                                        0,
744                                        true);
745     (*env)[name + "[f]"] = stub;
746   }
747
748
749   void register_built_in_functions(Context& ctx, Env* env)
750   {
751     using namespace Functions;
752     // RGB Functions
753     register_function(ctx, rgb_sig, rgb, env);
754     register_overload_stub(ctx, "rgba", env);
755     register_function(ctx, rgba_4_sig, rgba_4, 4, env);
756     register_function(ctx, rgba_2_sig, rgba_2, 2, env);
757     register_function(ctx, red_sig, red, env);
758     register_function(ctx, green_sig, green, env);
759     register_function(ctx, blue_sig, blue, env);
760     register_function(ctx, mix_sig, mix, env);
761     // HSL Functions
762     register_function(ctx, hsl_sig, hsl, env);
763     register_function(ctx, hsla_sig, hsla, env);
764     register_function(ctx, hue_sig, hue, env);
765     register_function(ctx, saturation_sig, saturation, env);
766     register_function(ctx, lightness_sig, lightness, env);
767     register_function(ctx, adjust_hue_sig, adjust_hue, env);
768     register_function(ctx, lighten_sig, lighten, env);
769     register_function(ctx, darken_sig, darken, env);
770     register_function(ctx, saturate_sig, saturate, env);
771     register_function(ctx, desaturate_sig, desaturate, env);
772     register_function(ctx, grayscale_sig, grayscale, env);
773     register_function(ctx, complement_sig, complement, env);
774     register_function(ctx, invert_sig, invert, env);
775     // Opacity Functions
776     register_function(ctx, alpha_sig, alpha, env);
777     register_function(ctx, opacity_sig, alpha, env);
778     register_function(ctx, opacify_sig, opacify, env);
779     register_function(ctx, fade_in_sig, opacify, env);
780     register_function(ctx, transparentize_sig, transparentize, env);
781     register_function(ctx, fade_out_sig, transparentize, env);
782     // Other Color Functions
783     register_function(ctx, adjust_color_sig, adjust_color, env);
784     register_function(ctx, scale_color_sig, scale_color, env);
785     register_function(ctx, change_color_sig, change_color, env);
786     register_function(ctx, ie_hex_str_sig, ie_hex_str, env);
787     // String Functions
788     register_function(ctx, unquote_sig, sass_unquote, env);
789     register_function(ctx, quote_sig, sass_quote, env);
790     register_function(ctx, str_length_sig, str_length, env);
791     register_function(ctx, str_insert_sig, str_insert, env);
792     register_function(ctx, str_index_sig, str_index, env);
793     register_function(ctx, str_slice_sig, str_slice, env);
794     register_function(ctx, to_upper_case_sig, to_upper_case, env);
795     register_function(ctx, to_lower_case_sig, to_lower_case, env);
796     // Number Functions
797     register_function(ctx, percentage_sig, percentage, env);
798     register_function(ctx, round_sig, round, env);
799     register_function(ctx, ceil_sig, ceil, env);
800     register_function(ctx, floor_sig, floor, env);
801     register_function(ctx, abs_sig, abs, env);
802     register_function(ctx, min_sig, min, env);
803     register_function(ctx, max_sig, max, env);
804     register_function(ctx, random_sig, random, env);
805     // List Functions
806     register_function(ctx, length_sig, length, env);
807     register_function(ctx, nth_sig, nth, env);
808     register_function(ctx, set_nth_sig, set_nth, env);
809     register_function(ctx, index_sig, index, env);
810     register_function(ctx, join_sig, join, env);
811     register_function(ctx, append_sig, append, env);
812     register_function(ctx, zip_sig, zip, env);
813     register_function(ctx, list_separator_sig, list_separator, env);
814     register_function(ctx, is_bracketed_sig, is_bracketed, env);
815     // Map Functions
816     register_function(ctx, map_get_sig, map_get, env);
817     register_function(ctx, map_merge_sig, map_merge, env);
818     register_function(ctx, map_remove_sig, map_remove, env);
819     register_function(ctx, map_keys_sig, map_keys, env);
820     register_function(ctx, map_values_sig, map_values, env);
821     register_function(ctx, map_has_key_sig, map_has_key, env);
822     register_function(ctx, keywords_sig, keywords, env);
823     // Introspection Functions
824     register_function(ctx, type_of_sig, type_of, env);
825     register_function(ctx, unit_sig, unit, env);
826     register_function(ctx, unitless_sig, unitless, env);
827     register_function(ctx, comparable_sig, comparable, env);
828     register_function(ctx, variable_exists_sig, variable_exists, env);
829     register_function(ctx, global_variable_exists_sig, global_variable_exists, env);
830     register_function(ctx, function_exists_sig, function_exists, env);
831     register_function(ctx, mixin_exists_sig, mixin_exists, env);
832     register_function(ctx, feature_exists_sig, feature_exists, env);
833     register_function(ctx, call_sig, call, env);
834     // Boolean Functions
835     register_function(ctx, not_sig, sass_not, env);
836     register_function(ctx, if_sig, sass_if, env);
837     // Misc Functions
838     register_function(ctx, inspect_sig, inspect, env);
839     register_function(ctx, unique_id_sig, unique_id, env);
840     // Selector functions
841     register_function(ctx, selector_nest_sig, selector_nest, env);
842     register_function(ctx, selector_append_sig, selector_append, env);
843     register_function(ctx, selector_extend_sig, selector_extend, env);
844     register_function(ctx, selector_replace_sig, selector_replace, env);
845     register_function(ctx, selector_unify_sig, selector_unify, env);
846     register_function(ctx, is_superselector_sig, is_superselector, env);
847     register_function(ctx, simple_selectors_sig, simple_selectors, env);
848     register_function(ctx, selector_parse_sig, selector_parse, env);
849   }
850
851   void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
852   {
853     while (descrs && *descrs) {
854       register_c_function(ctx, env, *descrs);
855       ++descrs;
856     }
857   }
858   void register_c_function(Context& ctx, Env* env, Sass_Function_Entry descr)
859   {
860     Definition_Ptr def = make_c_function(descr, ctx);
861     def->environment(env);
862     (*env)[def->name() + "[f]"] = def;
863   }
864
865 }