Skip to content
mgreter edited this page Nov 17, 2014 · 16 revisions

C-Interface

Usage

#include "sass_context.h"

The old interface may still work

#include "sass_interface.h"

Internals

Data is stored internally in structs:

struct sass_options;
struct sass_context : sass_options;
struct sass_file_context : sass_context;
struct sass_data_context : sass_context;

This mirrors very well how libsass uses these structures.

  • sass_options holds everything you feed in before the compilation. It also hosts input_path and output_path options, because they are used to generate/calculate relative links in source-maps. The input_path is shared with sass_file_context.
  • sass_context holds all the data returned by the compilation step.
  • sass_file_context is a specific implementation that requires no additional fields
  • sass_data_context is a specific implementation that adds the input_source field

Structs can be down-casted to access its context or options.

Common Pitfalls

input_path

The input_path is part of sass_options, but it also is the main option for sass_file_context. It is also used to generate relative file links in source-maps. Therefore it is pretty usefull to pass this information, if you have a sass_data_context and know the original path.

output_path

Be aware that libsass does not write the output file itself. This option merely exists to give libsass the proper information to generate links in source-maps. The file has to be written to the disk by the binding/implementation. If the output_path is omitted, libsass tries to extrapolate one from the input_path by replacing (or adding) the file ending with .css.

Internal structs

sass_options

// Precision for fractional numbers
int precision;
// Output style for the generated css code
// A value from above SASS_STYLE_* constants
int output_style;
// Emit comments in the generated CSS indicating
// the corresponding source line.
bool source_comments;
// embed sourceMappingUrl as data uri
bool source_map_embed;
// embed include contents in maps
bool source_map_contents;
// Disable sourceMappingUrl in css output
bool omit_source_map_url;
// Treat source_string as sass (as opposed to scss)
bool is_indented_syntax_src;
// The input path is used for source map
// generating. It can be used to define
// something with string compilation or to
// overload the input file path. It is
// set to "stdin" for data contexts and
// to the input file on file contexts.
char* input_path;
// The output path is used for source map
// generating. Libsass will not write to
// this file, it is just used to create
// information in source-maps etc.
char* output_path;
// For the image-url Sass function
char* image_path;
// Colon-separated list of paths
// Semicolon-separated on Windows
char* include_path;
// Additional include paths
// Must be null delimited
char** include_paths;
// Path to source map file
// Enables the source map generating
// Used to create sourceMappingUrl
char* source_map_file;
// Custom functions that can be called from sccs code
Sass_C_Function_List c_functions;
// Callback to overload imports
Sass_C_Import_Callback importer;

sass_context

// generated output data
char* output_string;
// generated source map json
char* source_map_string;
// error status
int error_status;
char* error_json;
char* error_message;
// error position
char* error_file;
size_t error_line;
size_t error_column;
// report imported files
char** included_files;

sass_file_context

// no additional fields required
// input_path is already on options

sass_data_context

// provided source string
const char* source_string;

Sass_Context API

// Forward declaration
struct Sass_Compiler;

// Forward declaration
struct Sass_Options;
struct Sass_Context; // : Sass_Options
struct Sass_File_Context; // : Sass_Context
struct Sass_Data_Context; // : Sass_Context

// Create and initialize an option struct
struct Sass_Options* sass_make_options (void);
// Create and initialize a specific context
struct Sass_File_Context* sass_make_file_context (const char* input_path);
struct Sass_Data_Context* sass_make_data_context (char* source_string);

// Call the compilation step for the specific context
int sass_compile_file_context (struct Sass_File_Context* ctx);
int sass_compile_data_context (struct Sass_Data_Context* ctx);

// Create a sass compiler instance for more control
struct Sass_Compiler* sass_make_file_compiler (struct Sass_File_Context* file_ctx);
struct Sass_Compiler* sass_make_data_compiler (struct Sass_Data_Context* data_ctx);

// Execute the different compilation steps individually
// Usefull if you only want to query the included files
int sass_compiler_parse(struct Sass_Compiler* compiler);
int sass_compiler_execute(struct Sass_Compiler* compiler);

// Release all memory allocated with the compiler
// This does _not_ include any contexts or options
void sass_delete_compiler(struct Sass_Compiler* compiler);

// Release all memory allocated and also ourself
void sass_delete_file_context (struct Sass_File_Context* ctx);
void sass_delete_data_context (struct Sass_Data_Context* ctx);

// Getters for context from specific implementation
struct Sass_Context* sass_file_context_get_context (struct Sass_File_Context* file_ctx);
struct Sass_Context* sass_data_context_get_context (struct Sass_Data_Context* data_ctx);

// Getters for context options from Sass_Context
struct Sass_Options* sass_context_get_options (struct Sass_Context* ctx);
struct Sass_Options* sass_file_context_get_options (struct Sass_File_Context* file_ctx);
struct Sass_Options* sass_data_context_get_options (struct Sass_Data_Context* data_ctx);
void sass_file_context_set_options (struct Sass_File_Context* file_ctx, struct Sass_Options* opt);
void sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct Sass_Options* opt);


// Getters for options
int sass_option_get_precision (struct Sass_Options* options);
enum Sass_Output_Style sass_option_get_output_style (struct Sass_Options* options);
bool sass_option_get_source_comments (struct Sass_Options* options);
bool sass_option_get_source_map_embed (struct Sass_Options* options);
bool sass_option_get_source_map_contents (struct Sass_Options* options);
bool sass_option_get_omit_source_map_url (struct Sass_Options* options);
bool sass_option_get_is_indented_syntax_src (struct Sass_Options* options);
const char* sass_option_get_input_path (struct Sass_Options* options);
const char* sass_option_get_output_path (struct Sass_Options* options);
const char* sass_option_get_image_path (struct Sass_Options* options);
const char* sass_option_get_include_path (struct Sass_Options* options);
const char* sass_option_get_source_map_file (struct Sass_Options* options);
Sass_C_Function_List sass_option_get_c_functions (struct Sass_Options* options);
Sass_C_Import_Callback sass_option_get_importer (struct Sass_Options* options);

// Setters for options
void sass_option_set_precision (struct Sass_Options* options, int precision);
void sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style);
void sass_option_set_source_comments (struct Sass_Options* options, bool source_comments);
void sass_option_set_source_map_embed (struct Sass_Options* options, bool source_map_embed);
void sass_option_set_source_map_contents (struct Sass_Options* options, bool source_map_contents);
void sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url);
void sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src);
void sass_option_set_input_path (struct Sass_Options* options, const char* input_path);
void sass_option_set_output_path (struct Sass_Options* options, const char* output_path);
void sass_option_set_image_path (struct Sass_Options* options, const char* image_path);
void sass_option_set_include_path (struct Sass_Options* options, const char* include_path);
void sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
void sass_option_set_c_functions (struct Sass_Options* options, Sass_C_Function_List c_functions);
void sass_option_set_importer (struct Sass_Options* options, Sass_C_Import_Callback importer);


// Getter for context
const char* sass_context_get_output_string (struct Sass_Context* ctx);
int sass_context_get_error_status (struct Sass_Context* ctx);
const char* sass_context_get_error_json (struct Sass_Context* ctx);
const char* sass_context_get_error_message (struct Sass_Context* ctx);
const char* sass_context_get_error_file (struct Sass_Context* ctx);
size_t sass_context_get_error_line (struct Sass_Context* ctx);
size_t sass_context_get_error_column (struct Sass_Context* ctx);
const char* sass_context_get_source_map_string (struct Sass_Context* ctx);
char** sass_context_get_included_files (struct Sass_Context* ctx);


// Setters for specific data context option
// const char* sass_data_context_get_source_string (struct Sass_Data_Context* ctx);
void sass_data_context_set_source_string (struct Sass_Data_Context* ctx, char* source_string);

// Push function for include paths (no manipulation support for now)
void sass_option_push_include_path (struct Sass_Options* options, const char* path);

Internal Sass_Context struct

// Input behaviours
enum Sass_Input_Style {
  SASS_CONTEXT_NULL,
  SASS_CONTEXT_FILE,
  SASS_CONTEXT_DATA,
  SASS_CONTEXT_FOLDER
};

// simple linked list
struct string_list {
  string_list* next;
  char* string;
};

// sass config options structure
struct Sass_Options {

  // Precision for fractional numbers
  int precision;

  // Output style for the generated css code
  // A value from above SASS_STYLE_* constants
  enum Sass_Output_Style output_style;

  // Emit comments in the generated CSS indicating
  // the corresponding source line.
  bool source_comments;

  // embed sourceMappingUrl as data uri
  bool source_map_embed;

  // embed include contents in maps
  bool source_map_contents;

  // Disable sourceMappingUrl in css output
  bool omit_source_map_url;

  // Treat source_string as sass (as opposed to scss)
  bool is_indented_syntax_src;

  // The input path is used for source map
  // generation. It can be used to define
  // something with string compilation or to
  // overload the input file path. It is
  // set to "stdin" for data contexts and
  // to the input file on file contexts.
  char* input_path;

  // The output path is used for source map
  // generation. Libsass will not write to
  // this file, it is just used to create
  // information in source-maps etc.
  char* output_path;

  // For the image-url Sass function
  char* image_path;

  // Colon-separated list of paths
  // Semicolon-separated on Windows
  // Maybe use array interface instead?
  char* include_path;

  // Include path (linked string list)
  struct string_list* include_paths;

  // Path to source map file
  // Enables source map generation
  // Used to create sourceMappingUrl
  char* source_map_file;

  // Custom functions that can be called from sccs code
  Sass_C_Function_List c_functions;

  // Callback to overload imports
  Sass_C_Import_Callback importer;

};

// base for all contexts
struct Sass_Context : Sass_Options
{

  // store context type info
  enum Sass_Input_Style type;

  // generated output data
  char* output_string;

  // generated source map json
  char* source_map_string;

  // error status
  int error_status;
  char* error_json;
  char* error_message;
  // error position
  char* error_file;
  size_t error_line;
  size_t error_column;

  // report imported files
  char** included_files;

};

// struct for file compilation
struct Sass_File_Context : Sass_Context {

  // no additional fields required
  // input_path is already on options

};

// struct for data compilation
struct Sass_Data_Context : Sass_Context {

  // provided source string
  char* source_string;

};

// Compiler states
enum Sass_Compiler_State {
  SASS_COMPILER_CREATED,
  SASS_COMPILER_PARSED,
  SASS_COMPILER_EXECUTED
};

// link c and cpp context
struct Sass_Compiler {
  // progress status
  Sass_Compiler_State state;
  // original c context
  Sass_Context* c_ctx;
  // Sass::Context
  void* cpp_ctx;
  // Sass::Block
  void* root;
};

Sass_Value API

// Forward declaration
union Sass_Value;

// Type for Sass values
enum Sass_Tag {
  SASS_BOOLEAN,
  SASS_NUMBER,
  SASS_COLOR,
  SASS_STRING,
  SASS_LIST,
  SASS_MAP,
  SASS_NULL,
  SASS_ERROR
};

// Tags for denoting Sass list separators
enum Sass_Separator {
  SASS_COMMA,
  SASS_SPACE
};

// Return the sass tag for a generic sass value
// Check is needed before accessing specific values!
enum Sass_Tag sass_value_get_tag (union Sass_Value* v);

// Check value to be of a specific type
// Can also be used before accessing properties!
bool sass_value_is_null (union Sass_Value* v);
bool sass_value_is_number (union Sass_Value* v);
bool sass_value_is_string (union Sass_Value* v);
bool sass_value_is_boolean (union Sass_Value* v);
bool sass_value_is_color (union Sass_Value* v);
bool sass_value_is_list (union Sass_Value* v);
bool sass_value_is_map (union Sass_Value* v);
bool sass_value_is_error (union Sass_Value* v);

// Getters and setters for Sass_Number
double sass_number_get_value (union Sass_Value* v);
void sass_number_set_value (union Sass_Value* v, double value);
const char* sass_number_get_unit (union Sass_Value* v);
void sass_number_set_unit (union Sass_Value* v, char* unit);

// Getters and setters for Sass_String
const char* sass_string_get_value (union Sass_Value* v);
void sass_string_set_value (union Sass_Value* v, char* value);

// Getters and setters for Sass_Boolean
bool sass_boolean_get_value (union Sass_Value* v);
void sass_boolean_set_value (union Sass_Value* v, bool value);

// Getters and setters for Sass_Color
double sass_color_get_r (union Sass_Value* v);
void sass_color_set_r (union Sass_Value* v, double r);
double sass_color_get_g (union Sass_Value* v);
void sass_color_set_g (union Sass_Value* v, double g);
double sass_color_get_b (union Sass_Value* v);
void sass_color_set_b (union Sass_Value* v, double b);
double sass_color_get_a (union Sass_Value* v);
void sass_color_set_a (union Sass_Value* v, double a);

// Getter for the number of items in list
size_t sass_list_get_length (union Sass_Value* v);
// Getters and setters for Sass_List
enum Sass_Separator sass_list_get_separator (union Sass_Value* v);
void sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
// Getters and setters for Sass_List values
union Sass_Value* sass_list_get_value (union Sass_Value* v, size_t i);
void sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);

// Getter for the number of items in map
size_t sass_map_get_length (union Sass_Value* v);
// Getters and setters for Sass_List keys and values
union Sass_Value* sass_map_get_key (union Sass_Value* v, size_t i);
void sass_map_set_key (union Sass_Value* v, size_t i, union Sass_Value*);
union Sass_Value* sass_map_get_value (union Sass_Value* v, size_t i);
void sass_map_set_value (union Sass_Value* v, size_t i, union Sass_Value*);

// Getters and setters for Sass_Error
char* sass_error_get_message (union Sass_Value* v);
void sass_error_set_message (union Sass_Value* v, char* msg);

// Creator functions for all value types
union Sass_Value* sass_make_null    (void);
union Sass_Value* sass_make_boolean (bool val);
union Sass_Value* sass_make_string  (const char* val);
union Sass_Value* sass_make_number  (double val, const char* unit);
union Sass_Value* sass_make_color   (double r, double g, double b, double a);
union Sass_Value* sass_make_list    (size_t len, enum Sass_Separator sep);
union Sass_Value* sass_make_map     (size_t len);
union Sass_Value* sass_make_error   (const char* msg);

// Generic destructor function for all types
// Will release memory of all associated Sass_Values
// Means we will delete recursively for lists and maps
void sass_delete_value (union Sass_Value* val);

Internal Sass_Value struct

struct Sass_Unknown {
  enum Sass_Tag tag;
};

struct Sass_Boolean {
  enum Sass_Tag tag;
  bool          value;
};

struct Sass_Number {
  enum Sass_Tag tag;
  double        value;
  char*         unit;
};

struct Sass_Color {
  enum Sass_Tag tag;
  double        r;
  double        g;
  double        b;
  double        a;
};

struct Sass_String {
  enum Sass_Tag tag;
  char*         value;
};

struct Sass_List {
  enum Sass_Tag       tag;
  enum Sass_Separator separator;
  size_t              length;
  // null terminated "array"
  union Sass_Value**  values;
};

struct Sass_Map {
  enum Sass_Tag        tag;
  size_t               length;
  struct Sass_MapPair* pairs;
};

struct Sass_Null {
  enum Sass_Tag tag;
};

struct Sass_Error {
  enum Sass_Tag tag;
  char*         message;
};

union Sass_Value {
  struct Sass_Unknown unknown;
  struct Sass_Boolean boolean;
  struct Sass_Number  number;
  struct Sass_Color   color;
  struct Sass_String  string;
  struct Sass_List    list;
  struct Sass_Map     map;
  struct Sass_Null    null;
  struct Sass_Error   error;
};

struct Sass_MapPair {
  union Sass_Value* key;
  union Sass_Value* value;
};

Sass_C_Function API

// Forward declaration
struct Sass_C_Import_Descriptor;

// Typedef defining the custom importer callback
typedef struct Sass_C_Import_Descriptor (*Sass_C_Import_Callback);
// Typedef defining the importer c function prototype
typedef struct Sass_Import** (*Sass_C_Import_Fn) (const char* url, void* cookie);

// Creators for custom importer callback (with some additional pointer)
// The pointer is mostly used to store the callback into the actual binding
Sass_C_Import_Callback sass_make_importer (Sass_C_Import_Fn, void* cookie);

// Getters for import function descriptors
Sass_C_Import_Fn sass_import_get_function (Sass_C_Import_Callback fn);
void* sass_import_get_cookie (Sass_C_Import_Callback fn);


// Creator for sass custom importer return argument list
struct Sass_Import** sass_make_import_list (size_t length);
// Creator for a single import entry returned by the custom importer inside the list
struct Sass_Import* sass_make_import_entry (const char* path, char* source, char* srcmap);

// Setters to insert an entry into the import list (you may also use [] access directly)
// Since we are dealing with pointers they should have a guaranteed and fixed size
void sass_import_set_list_entry (struct Sass_Import** list, size_t idx, struct Sass_Import* entry);
struct Sass_Import* sass_import_get_list_entry (struct Sass_Import** list, size_t idx);

// Getters for import entry
const char* sass_import_get_path (struct Sass_Import*);
const char* sass_import_get_source (struct Sass_Import*);
const char* sass_import_get_srcmap (struct Sass_Import*);
// Explicit functions to take ownership of these items
// The property on our struct will be reset to NULL
char* sass_import_take_source (struct Sass_Import*);
char* sass_import_take_srcmap (struct Sass_Import*);

// Deallocator for associated memory (incl. entries)
void sass_delete_import_list (struct Sass_Import**);


// Forward declaration
struct Sass_C_Function_Descriptor;

// Typedef defining null terminated list of custom callbacks
typedef struct Sass_C_Function_Descriptor* (*Sass_C_Function_List);
typedef struct Sass_C_Function_Descriptor (*Sass_C_Function_Callback);
// Typedef defining custom function prototype and its return value type
typedef union Sass_Value*(*Sass_C_Function) (union Sass_Value*, void *cookie);


// Creators for sass function list and function descriptors
Sass_C_Function_List sass_make_function_list (size_t length);
Sass_C_Function_Callback sass_make_function (const char* signature, Sass_C_Function fn, void* cookie);

// Getters for custom function descriptors
const char* sass_function_get_signature (Sass_C_Function_Callback fn);
Sass_C_Function sass_function_get_function (Sass_C_Function_Callback fn);
void* sass_function_get_cookie (Sass_C_Function_Callback fn);

Internal Sass_C_Function structs

// External import entry
struct Sass_Import {
  char* path;
  char* source;
  char* srcmap;
};

// Struct to hold importer callback
struct Sass_C_Import_Descriptor {
  Sass_C_Import_Fn function;
  void*            cookie;
};

// Struct to hold custom function callback
struct Sass_C_Function_Descriptor {
  const char*     signature;
  Sass_C_Function function;
  void*           cookie;
};

Example from [perl-libsass] 1

init_sass_options

SV** input_path_sv          = hv_fetchs(perl_options, "input_path",           false);
SV** output_path_sv         = hv_fetchs(perl_options, "output_path",          false);
SV** output_style_sv        = hv_fetchs(perl_options, "output_style",         false);
SV** source_comments_sv     = hv_fetchs(perl_options, "source_comments",      false);
SV** omit_source_map_sv     = hv_fetchs(perl_options, "omit_source_map",      false);
SV** omit_source_map_url_sv = hv_fetchs(perl_options, "omit_source_map_url",  false);
SV** source_map_contents_sv = hv_fetchs(perl_options, "source_map_contents",  false);
SV** source_map_embed_sv    = hv_fetchs(perl_options, "source_map_embed",     false);
SV** include_paths_sv       = hv_fetchs(perl_options, "include_paths",        false);
SV** precision_sv           = hv_fetchs(perl_options, "precision",            false);
SV** image_path_sv          = hv_fetchs(perl_options, "image_path",           false);
SV** source_map_file_sv     = hv_fetchs(perl_options, "source_map_file",      false);
SV** sass_functions_sv      = hv_fetchs(perl_options, "sass_functions",       false);
SV** importer_sv            = hv_fetchs(perl_options, "importer",             false);

if (input_path_sv)          sass_option_set_input_path          (sass_options, safe_svpv(*input_path_sv, ""));
if (output_path_sv)         sass_option_set_output_path         (sass_options, safe_svpv(*output_path_sv, ""));
if (output_style_sv)        sass_option_set_output_style        (sass_options, SvUV(*output_style_sv));
if (source_comments_sv)     sass_option_set_source_comments     (sass_options, SvTRUE(*source_comments_sv));
if (omit_source_map_sv)     sass_option_set_omit_source_map_url (sass_options, SvTRUE(*omit_source_map_sv));
if (omit_source_map_url_sv) sass_option_set_omit_source_map_url (sass_options, SvTRUE(*omit_source_map_url_sv));
if (source_map_contents_sv) sass_option_set_source_map_contents (sass_options, SvTRUE(*source_map_contents_sv));
if (source_map_embed_sv)    sass_option_set_source_map_embed    (sass_options, SvTRUE(*source_map_embed_sv));
if (include_paths_sv)       sass_option_set_include_path        (sass_options, safe_svpv(*include_paths_sv, ""));
if (precision_sv)           sass_option_set_precision           (sass_options, SvUV(*precision_sv));
if (image_path_sv)          sass_option_set_image_path          (sass_options, safe_svpv(*image_path_sv, ""));
if (source_map_file_sv)     sass_option_set_source_map_file     (sass_options, safe_svpv(*source_map_file_sv, ""));

if (importer_sv) { sass_option_set_importer(sass_options, sass_make_importer(sass_importer, *importer_sv)); }

compile_sass_file

struct Sass_Data_Context* data_ctx = sass_make_data_context(input_string);
struct Sass_Context* ctx = sass_data_context_get_context(data_ctx);
struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
SV* err = init_sass_options(ctx_opt, options);
if (!SvTRUE(err)) sass_compile_data_context(data_ctx);
finalize_sass_context(ctx, RETVAL, err);
sass_delete_data_context(data_ctx);

Or if you only want to query included_files:

struct Sass_File_Context* file_ctx = sass_make_file_context(input_path);
struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
SV* err = init_sass_options(ctx_opt, options);
if (!SvTRUE(err)) {
  struct Sass_Compiler* compiler = sass_make_file_compiler(file_ctx);
  sass_compiler_parse(compiler);
  // included_files is already available
  char** included_files = sass_context_get_included_files(ctx);
  // sass_compiler_execute(compiler);
  sass_delete_compiler(compiler);
}
finalize_sass_context(ctx, RETVAL, err);
sass_delete_file_context(file_ctx);

sass_importer

struct Sass_Import** sass_importer(const char* url, void* cookie)
{
  struct Sass_Import** incs = sass_make_import_list(2);
  incs[0] = sass_make_import_entry("virtual.scss", strdup(source), 0);
  incs[1] = sass_make_import_entry("include.scss", 0, 0);
  return incs;
}