Blame docs/custom-functions-internal.md

Packit bfcc33
# Developer Documentation
Packit bfcc33
Packit bfcc33
Custom functions are internally represented by `struct Sass_C_Function_Descriptor`.
Packit bfcc33
Packit bfcc33
## Sass_C_Function_Descriptor
Packit bfcc33
Packit bfcc33
```C
Packit bfcc33
struct Sass_C_Function_Descriptor {
Packit bfcc33
  const char*      signature;
Packit bfcc33
  Sass_C_Function  function;
Packit bfcc33
  void*            cookie;
Packit bfcc33
};
Packit bfcc33
```
Packit bfcc33
Packit bfcc33
- `signature`: The function declaration, like `foo($bar, $baz:1)`
Packit bfcc33
- `function`:  Reference to the C function callback
Packit bfcc33
- `cookie`:    any pointer you want to attach
Packit bfcc33
Packit bfcc33
### signature
Packit bfcc33
Packit bfcc33
The signature defines how the function can be invoked. It also declares which arguments are required and which are optional.  Required arguments will be enforced by LibSass and a Sass error is thrown in the event a call as missing an argument. Optional arguments only need to be present when you want to overwrite the default value.
Packit bfcc33
Packit bfcc33
    foo($bar, $baz: 2)
Packit bfcc33
Packit bfcc33
In this example, `$bar` is required and will error if not passed. `$baz` is optional and the default value of it is 2. A call like `foo(10)` is therefore equal to `foo(10, 2)`, while `foo()` will produce an error.
Packit bfcc33
Packit bfcc33
### function
Packit bfcc33
Packit bfcc33
The callback function needs to be of the following form:
Packit bfcc33
Packit bfcc33
```C
Packit bfcc33
union Sass_Value* call_sass_function(
Packit bfcc33
    const union Sass_Value* s_args,
Packit bfcc33
    void*                   cookie
Packit bfcc33
) {
Packit bfcc33
  return sass_clone_value(s_args);
Packit bfcc33
}
Packit bfcc33
```
Packit bfcc33
Packit bfcc33
### cookie
Packit bfcc33
Packit bfcc33
The cookie can hold any pointer you want. In the `perl-libsass` implementation it holds the structure with the reference of the actual registered callback into the perl interpreter. Before that call `perl-libsass` will convert all `Sass_Values` to corresponding perl data types (so they can be used natively inside the perl interpretor). The callback can also return a `Sass_Value`. In `perl-libsass` the actual function returns a perl value, which has to be converted before `libsass` can work with it again!
Packit bfcc33
Packit bfcc33
## Sass_Values
Packit bfcc33
Packit bfcc33
```C
Packit bfcc33
// allocate memory (copies passed strings)
Packit bfcc33
union Sass_Value* make_sass_boolean (int val);
Packit bfcc33
union Sass_Value* make_sass_number  (double val, const char* unit);
Packit bfcc33
union Sass_Value* make_sass_color   (double r, double g, double b, double a);
Packit bfcc33
union Sass_Value* make_sass_string  (const char* val);
Packit bfcc33
union Sass_Value* make_sass_list    (size_t len, enum Sass_Separator sep);
Packit bfcc33
union Sass_Value* make_sass_map     (size_t len);
Packit bfcc33
union Sass_Value* make_sass_null    ();
Packit bfcc33
union Sass_Value* make_sass_error   (const char* msg);
Packit bfcc33
Packit bfcc33
// Make a deep cloned copy of the given sass value
Packit bfcc33
union Sass_Value* sass_clone_value (const union Sass_Value* val);
Packit bfcc33
Packit bfcc33
// deallocate memory (incl. all copied memory)
Packit bfcc33
void sass_delete_value (const union Sass_Value* val);
Packit bfcc33
```
Packit bfcc33
Packit bfcc33
## Example main.c
Packit bfcc33
Packit bfcc33
```C
Packit bfcc33
#include <stdio.h>
Packit bfcc33
#include <stdint.h>
Packit bfcc33
#include "sass/context.h"
Packit bfcc33
Packit bfcc33
union Sass_Value* call_fn_foo(const union Sass_Value* s_args, void* cookie)
Packit bfcc33
{
Packit bfcc33
  // we actually abuse the void* to store an "int"
Packit bfcc33
  return sass_make_number((size_t)cookie, "px");
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
int main( int argc, const char* argv[] )
Packit bfcc33
{
Packit bfcc33
Packit bfcc33
  // get the input file from first argument or use default
Packit bfcc33
  const char* input = argc > 1 ? argv[1] : "styles.scss";
Packit bfcc33
Packit bfcc33
  // create the file context and get all related structs
Packit bfcc33
  struct Sass_File_Context* file_ctx = sass_make_file_context(input);
Packit bfcc33
  struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
Packit bfcc33
  struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
Packit bfcc33
Packit bfcc33
  // allocate a custom function caller
Packit bfcc33
  Sass_C_Function_Callback fn_foo =
Packit bfcc33
    sass_make_function("foo()", call_fn_foo, (void*)42);
Packit bfcc33
Packit bfcc33
  // create list of all custom functions
Packit bfcc33
  Sass_C_Function_List fn_list = sass_make_function_list(1);
Packit bfcc33
  sass_function_set_list_entry(fn_list, 0, fn_foo);
Packit bfcc33
  sass_option_set_c_functions(ctx_opt, fn_list);
Packit bfcc33
Packit bfcc33
  // context is set up, call the compile step now
Packit bfcc33
  int status = sass_compile_file_context(file_ctx);
Packit bfcc33
Packit bfcc33
  // print the result or the error to the stdout
Packit bfcc33
  if (status == 0) puts(sass_context_get_output_string(ctx));
Packit bfcc33
  else puts(sass_context_get_error_message(ctx));
Packit bfcc33
Packit bfcc33
  // release allocated memory
Packit bfcc33
  sass_delete_file_context(file_ctx);
Packit bfcc33
Packit bfcc33
  // exit status
Packit bfcc33
  return status;
Packit bfcc33
Packit bfcc33
}
Packit bfcc33
```
Packit bfcc33
Packit bfcc33
## Compile main.c
Packit bfcc33
Packit bfcc33
```bash
Packit bfcc33
gcc -c main.c -o main.o
Packit bfcc33
gcc -o sample main.o -lsass
Packit bfcc33
echo "foo { margin: foo(); }" > foo.scss
Packit bfcc33
./sample foo.scss => "foo { margin: 42px }"
Packit bfcc33
```