├── .gitignore ├── .gitmodules ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── appveyor.yml ├── examples ├── _imported.scss ├── compile_sass.rs └── simple.scss ├── sass-sys ├── Cargo.toml ├── LICENSE ├── build.rs └── src │ ├── bindings.rs │ └── lib.rs └── src ├── bindings ├── context.rs ├── mod.rs ├── options.rs ├── ptr.rs └── util.rs ├── lib.rs ├── main.rs └── options.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | .idea 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sass-sys/libsass"] 2 | path = sass-sys/libsass 3 | url = https://github.com/sass/libsass.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | 4 | matrix: 5 | include: 6 | # Linux 7 | - env: TARGET=x86_64-unknown-linux-gnu 8 | # OSX 9 | - env: TARGET=x86_64-apple-darwin 10 | os: osx 11 | 12 | notifications: 13 | email: false 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.2.1 (2017/12/29) 4 | 5 | - Fix potential memory leak 6 | - Use colons to join include paths on Unix 7 | 8 | ## 0.2.0 (2017/07/24) 9 | 10 | - Make `OutputStyle` public 11 | - `compile_file` now takes a path 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sass-rs" 3 | version = "0.2.2" 4 | authors = [ 5 | "Marius Seritan ", 6 | "Vincent Prouillet " 7 | ] 8 | keywords = ["sass", "scss", "ffi"] 9 | description = "Higher level binding for the Sass library" 10 | license = "MIT" 11 | readme = "README.md" 12 | repository = "https://github.com/compass-rs/sass-rs.git" 13 | homepage = "https://github.com/compass-rs/sass-rs" 14 | categories = ["web-programming", "development-tools::build-utils"] 15 | 16 | [lib] 17 | name = "sass_rs" 18 | 19 | [dependencies] 20 | sass-sys = { version = "0.4", path = "./sass-sys" } 21 | libc = "0.2" 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 compass-rs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sass-rs 2 | 3 | [![Build Status](https://travis-ci.org/compass-rs/sass-rs.svg?branch=master)](https://travis-ci.org/compass-rs/sass-rs) 4 | [![Windows build status](https://ci.appveyor.com/api/projects/status/j8enle2iod2nxtor/branch/master?svg=true)](https://ci.appveyor.com/project/Keats/sass-rs-rmnm5/branch/master) 5 | ![Maintenance status](https://img.shields.io/maintenance/no/2021) 6 | 7 | [Api documentation on docs.rs](https://docs.rs/sass-rs) 8 | 9 | -- 10 | 11 | **This crate is not maintained anymore as libsass is deprecated. Consider using or instead.** 12 | 13 | -- 14 | 15 | This crate is a wrapper around [libsass](https://github.com/sass/libsass), currently tracking 16 | [v3.6.4](https://github.com/sass/libsass/releases/tag/3.6.4). 17 | 18 | To build this crate on Windows, you will need to have Visual Studio installed. 19 | 20 | You can control the number of CPU used to build `libsass` by setting the `MAKE_LIBSASS_JOBS` variable to the desired value. It defaults to the number of CPUs in the machine. 21 | 22 | ## Binary 23 | This package also provides a small binary that can be `cargo install`ed to convert Sass files and print the output CSS. 24 | Example usage: 25 | 26 | ```bash 27 | $ sass-rs < source/style.scss # for SCSS 28 | $ sass-rs --sass < source/style.sass # for SASS 29 | $ sass-rs --sass --expanded < source/style.sass 30 | $ sass-rs --sass --compact < source/style.sass 31 | $ sass-rs --sass --compressed < source/style.sass 32 | $ sass-rs --sass --compressed < source/style.sass > build/style.css 33 | ``` 34 | 35 | This is a small added feature that isn't meant to fulfill every usecases. If you want to have something added to the binary, do a PR as I will not implement it myself. 36 | 37 | ## Not supported yet 38 | [Importers](https://github.com/sass/libsass/blob/master/docs/api-importer.md) and 39 | [functions](https://github.com/sass/libsass/blob/master/docs/api-function.md) are not supported yet. 40 | 41 | 42 | ## Building (Windows) 43 | 44 | Windows compilation using VS 2019 requires that all the environment variables for MSBuild to be availble. 45 | 46 | An indicator that the environment is not properly setup is the following error message: 47 | 48 | ``` 49 | error MSB4019: The imported project "C:\Microsoft.Cpp.Default.props" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk. 50 | ``` 51 | 52 | If you find this error, you have a couple of of options to select: 53 | 54 | - [Easiest] Open the `Developer Command Prompt for VS 2019` application to compile the project. This terminal will setup all the needed environment variables to let it compile. 55 | - Setup the environment variables (eg: `PATH`, `LIB`) as [documented on Microsoft's website](https://docs.microsoft.com/en-us/cpp/build/setting-the-path-and-environment-variables-for-command-line-builds?view=vs-2019) 56 | - Install the complete setup of Visual Studio 2015 - not only the Visual C++ Build tools 57 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | os: Visual Studio 2017 2 | 3 | environment: 4 | global: 5 | PROJECT_NAME: sass 6 | 7 | matrix: 8 | - TARGET: x86_64-pc-windows-msvc 9 | CHANNEL: stable 10 | PLATFORM: x86_64 11 | - TARGET: i686-pc-windows-msvc 12 | CHANNEL: stable 13 | PLATFORM: i686 14 | 15 | install: 16 | # Install Rust and Cargo 17 | - if "%PLATFORM%" == "i686" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 18 | - if "%PLATFORM%" == "x86_64" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64 19 | - curl -sSf -o rustup-init.exe https://win.rustup.rs 20 | - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y 21 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 22 | - rustc -Vv 23 | - cargo -V 24 | - git submodule update --init 25 | 26 | cache: 27 | - C:\Users\appveyor\.cargo\registry 28 | - target 29 | 30 | build: false 31 | 32 | test_script: 33 | - cargo test 34 | -------------------------------------------------------------------------------- /examples/_imported.scss: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /examples/compile_sass.rs: -------------------------------------------------------------------------------- 1 | /// Example file on how to compile a scss file. 2 | 3 | extern crate sass_rs; 4 | use sass_rs::{Options, compile_file}; 5 | 6 | 7 | pub fn main() { 8 | let mut args = std::env::args(); 9 | let _ = args.next(); 10 | let file = args.next().expect("Please pass in a file name"); 11 | println!("Compiling sass file: `{}`.", file); 12 | println!("> Default:\n{}", compile_file(&file, Options::default()).unwrap()); 13 | } 14 | -------------------------------------------------------------------------------- /examples/simple.scss: -------------------------------------------------------------------------------- 1 | $font-stack: Helvetica, sans-serif; 2 | $primary-color: #333; 3 | 4 | body { 5 | font: 100% $font-stack; 6 | color: $primary-color; 7 | content: foo(1px); 8 | } 9 | 10 | @import "imported"; 11 | -------------------------------------------------------------------------------- /sass-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "sass-sys" 4 | version = "0.4.22" 5 | authors = [ 6 | "Marius Seritan ", 7 | "Vincent Prouillet " 8 | ] 9 | links = "sass" 10 | build = "build.rs" 11 | 12 | keywords = ["sass", "ffi"] 13 | description = "Low level binding for the Sass library" 14 | license = "MIT" 15 | readme = "../README.md" 16 | repository = "https://github.com/compass-rs/sass-rs.git" 17 | homepage = "https://github.com/compass-rs/sass-rs" 18 | # https://github.com/NixOS/nixpkgs/issues/72972#issuecomment-554794824 19 | exclude = ["libsass/test/e2e/unicode-pwd"] 20 | 21 | [build-dependencies] 22 | pkg-config = "0.3" 23 | num_cpus = "1.9.0" 24 | # bindgen = "0.51" 25 | 26 | [dependencies] 27 | libc = "0.2" 28 | 29 | [target.'cfg(target_env = "msvc")'.build-dependencies] 30 | cc = "1.0" 31 | -------------------------------------------------------------------------------- /sass-sys/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /sass-sys/build.rs: -------------------------------------------------------------------------------- 1 | // extern crate bindgen; 2 | #[cfg(target_env = "msvc")] 3 | extern crate cc; 4 | extern crate pkg_config; 5 | extern crate num_cpus; 6 | 7 | use std::env; 8 | use std::fs; 9 | use std::path::{Path, PathBuf}; 10 | use std::process::{Command, Stdio}; 11 | 12 | // Automatically write bindings to libsass 13 | //#[allow(dead_code)] 14 | //fn write_bindings() { 15 | // let bindings = bindgen::Builder::default() 16 | // .header("libsass/include/sass.h") 17 | // .clang_arg("-Ilibsass/include") 18 | // // To avoid a test failing 19 | // .blacklist_type("max_align_t") 20 | // // we do static linking so it should be fine 21 | // // https://github.com/rust-lang/rust/issues/36927 22 | // .rustified_enum(".*") 23 | // .generate() 24 | // .expect("Unable to generate bindings"); 25 | // 26 | // // Write the bindings to the $OUT_DIR/bindings.rs file. 27 | // let out_path = PathBuf::from("src"); 28 | // bindings 29 | // .write_to_file(out_path.join("bindings.rs")) 30 | // .expect("Couldn't write bindings!"); 31 | //} 32 | 33 | macro_rules! t { 34 | ($e:expr) => (match $e { 35 | Ok(n) => n, 36 | Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e), 37 | }) 38 | } 39 | 40 | fn cp_r(dir: &Path, dest: &Path) { 41 | for entry in t!(fs::read_dir(dir)) { 42 | let entry = t!(entry); 43 | let path = entry.path(); 44 | let dst = dest.join(path.file_name().expect("Failed to get filename of path")); 45 | if t!(fs::metadata(&path)).is_file() { 46 | t!(fs::copy(path, dst)); 47 | } else { 48 | t!(fs::create_dir_all(&dst)); 49 | cp_r(&path, &dst); 50 | } 51 | } 52 | } 53 | 54 | fn get_libsass_folder() -> PathBuf { 55 | env::current_dir().expect("Failed to get the current directory").join("libsass") 56 | } 57 | 58 | #[cfg(target_os = "linux")] 59 | fn _compile(libprobe: fn(&str) -> bool) { 60 | if libprobe("stdc++") { 61 | println!("cargo:rustc-link-lib=dylib=stdc++"); 62 | } else if libprobe("c++_shared") { 63 | println!("cargo:rustc-link-lib=dylib=c++_shared"); 64 | } else if libprobe("c++") { 65 | println!("cargo:rustc-link-lib=dylib=c++"); 66 | } else { 67 | panic!("no c++ library found"); 68 | } 69 | } 70 | 71 | #[cfg(not(target_os = "linux"))] 72 | fn _compile(libprobe: fn(&str) -> bool) { 73 | if libprobe("c++_shared") { 74 | println!("cargo:rustc-link-lib=dylib=c++_shared"); 75 | } else if libprobe("c++") { 76 | println!("cargo:rustc-link-lib=dylib=c++"); 77 | } else if libprobe("stdc++") { 78 | println!("cargo:rustc-link-lib=dylib=stdc++"); 79 | } else { 80 | panic!("no c++ library found"); 81 | } 82 | } 83 | 84 | // linux/unix 85 | #[cfg(not(target_env = "msvc"))] 86 | fn compile() { 87 | let target = env::var("TARGET").expect("TARGET not found"); 88 | let src = get_libsass_folder(); 89 | let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found")); 90 | let build = dest.join("build"); 91 | t!(fs::create_dir_all(&build)); 92 | cp_r(&src, &build); 93 | let is_bsd = target.contains("dragonfly") 94 | || target.contains("freebsd") 95 | || target.contains("netbsd") 96 | || target.contains("openbsd"); 97 | let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string()); 98 | let r = Command::new(if is_bsd { "gmake" } else { "make" }) 99 | .current_dir(&build) 100 | .args(&["--jobs", &jobs]) 101 | .output() 102 | .expect("Failed to run make/gmake. Do you have it installed?"); 103 | 104 | if !r.status.success() { 105 | let err = String::from_utf8_lossy(&r.stderr); 106 | let out = String::from_utf8_lossy(&r.stdout); 107 | panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out); 108 | } 109 | 110 | println!( 111 | "cargo:rustc-link-search=native={}", 112 | build.join("lib").display() 113 | ); 114 | println!("cargo:rustc-link-lib=static=sass"); 115 | 116 | let libprobe = | lib: &str | -> bool { 117 | Command::new("cc") 118 | .arg("-xc++") 119 | .arg("-o/dev/null") 120 | .arg(format!("-l{}",lib)) 121 | .arg("-shared") 122 | .stderr(Stdio::null()) 123 | .status() 124 | .expect("Failed to run cc. Do you have it installed?") 125 | .success() 126 | }; 127 | _compile(libprobe); 128 | } 129 | 130 | // windows 131 | #[cfg(target_env = "msvc")] 132 | fn compile() { 133 | let src = get_libsass_folder(); 134 | let target = env::var("TARGET").expect("TARGET not found in environment"); 135 | let msvc_platform = if target.contains("x86_64") { 136 | "Win64" 137 | } else { 138 | "Win32" 139 | }; 140 | let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found in environment")); 141 | let build = dest.join("build"); 142 | t!(fs::create_dir_all(&build)); 143 | cp_r(&src, &build); 144 | 145 | // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade 146 | // libsass.sln to the current available IDE. Do nothing if no devenv.exe found 147 | let d = cc::windows_registry::find(target.as_str(), "devenv.exe"); 148 | if let Some(mut d) = d { 149 | let d = d 150 | .args(&["/upgrade", "win\\libsass.sln"]) 151 | .current_dir(&build) 152 | .output() 153 | .expect("Failed to run devenv. Do you have it installed?"); 154 | if !d.status.success() { 155 | let err = String::from_utf8_lossy(&d.stderr); 156 | let out = String::from_utf8_lossy(&d.stdout); 157 | println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out); 158 | } 159 | } 160 | 161 | let search = Command::new("where") 162 | .args(&["msbuild.exe"]) 163 | .output() 164 | .expect("Failed to run where: Could not search for msbuild.exe on path."); 165 | let mut msbuild = if search.status.success() { 166 | Command::new("msbuild.exe") 167 | } else { 168 | cc::windows_registry::find(target.as_str(), "msbuild.exe") 169 | .expect("Could not find msbuild.exe on the registry") 170 | }; 171 | 172 | let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string()); 173 | 174 | let r = msbuild 175 | .args(&[ 176 | "win\\libsass.sln", 177 | "/p:LIBSASS_STATIC_LIB=1", 178 | "/p:Configuration=Release", 179 | "/p:WholeProgramOptimization=false", 180 | "/p:UseMultiToolTask=true", 181 | format!("/m:{}", jobs).as_str(), 182 | format!("/p:Platform={}", msvc_platform).as_str(), 183 | ]) 184 | .current_dir(&build) 185 | .output() 186 | .expect("Failed to run msbuild. Do you have it installed?"); 187 | 188 | if !r.status.success() { 189 | let err = String::from_utf8_lossy(&r.stderr); 190 | let out = String::from_utf8_lossy(&r.stdout); 191 | panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out); 192 | } 193 | 194 | println!( 195 | "cargo:rustc-link-search=native={}", 196 | build.join("win").join("bin").display() 197 | ); 198 | println!("cargo:rustc-link-lib=static=libsass"); 199 | } 200 | 201 | fn main() { 202 | // Uncomment the line below to generate bindings. Doesn't work on CI as it 203 | // requires additional tooling 204 | // write_bindings(); 205 | 206 | // Is it already built? 207 | if pkg_config::find_library("libsass").is_ok() { 208 | return; 209 | } 210 | 211 | if !get_libsass_folder().join("Makefile").exists() { 212 | eprintln!(" 213 | Could not find libsass source 214 | Try running `git submodule update --init` if you are building from the repository 215 | "); 216 | std::process::exit(1); 217 | } 218 | 219 | compile(); 220 | } 221 | -------------------------------------------------------------------------------- /sass-sys/src/bindings.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen */ 2 | 3 | pub const true_: u32 = 1; 4 | pub const false_: u32 = 0; 5 | pub const __bool_true_false_are_defined: u32 = 1; 6 | pub const LIBSASS_VERSION: &'static [u8; 5usize] = b"[NA]\0"; 7 | pub const LIBSASS_LANGUAGE_VERSION: &'static [u8; 4usize] = b"3.5\0"; 8 | pub const SASS2SCSS_PRETTIFY_0: u32 = 0; 9 | pub const SASS2SCSS_PRETTIFY_1: u32 = 1; 10 | pub const SASS2SCSS_PRETTIFY_2: u32 = 2; 11 | pub const SASS2SCSS_PRETTIFY_3: u32 = 3; 12 | pub const SASS2SCSS_KEEP_COMMENT: u32 = 32; 13 | pub const SASS2SCSS_STRIP_COMMENT: u32 = 64; 14 | pub const SASS2SCSS_CONVERT_COMMENT: u32 = 128; 15 | pub type wchar_t = ::std::os::raw::c_int; 16 | #[repr(u32)] 17 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 18 | pub enum Sass_Output_Style { 19 | SASS_STYLE_NESTED = 0, 20 | SASS_STYLE_EXPANDED = 1, 21 | SASS_STYLE_COMPACT = 2, 22 | SASS_STYLE_COMPRESSED = 3, 23 | SASS_STYLE_INSPECT = 4, 24 | SASS_STYLE_TO_SASS = 5, 25 | SASS_STYLE_TO_CSS = 6, 26 | } 27 | extern "C" { 28 | pub fn sass_alloc_memory(size: usize) -> *mut ::std::os::raw::c_void; 29 | } 30 | extern "C" { 31 | pub fn sass_copy_c_string(str: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; 32 | } 33 | extern "C" { 34 | pub fn sass_free_memory(ptr: *mut ::std::os::raw::c_void); 35 | } 36 | extern "C" { 37 | pub fn sass_string_quote( 38 | str: *const ::std::os::raw::c_char, 39 | quote_mark: ::std::os::raw::c_char, 40 | ) -> *mut ::std::os::raw::c_char; 41 | } 42 | extern "C" { 43 | pub fn sass_string_unquote(str: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; 44 | } 45 | extern "C" { 46 | pub fn libsass_version() -> *const ::std::os::raw::c_char; 47 | } 48 | extern "C" { 49 | pub fn libsass_language_version() -> *const ::std::os::raw::c_char; 50 | } 51 | #[repr(C)] 52 | #[derive(Copy, Clone)] 53 | pub struct Sass_Value { 54 | _unused: [u8; 0], 55 | } 56 | #[repr(u32)] 57 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 58 | pub enum Sass_Tag { 59 | SASS_BOOLEAN = 0, 60 | SASS_NUMBER = 1, 61 | SASS_COLOR = 2, 62 | SASS_STRING = 3, 63 | SASS_LIST = 4, 64 | SASS_MAP = 5, 65 | SASS_NULL = 6, 66 | SASS_ERROR = 7, 67 | SASS_WARNING = 8, 68 | } 69 | #[repr(u32)] 70 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 71 | pub enum Sass_Separator { 72 | SASS_COMMA = 0, 73 | SASS_SPACE = 1, 74 | SASS_HASH = 2, 75 | } 76 | #[repr(u32)] 77 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 78 | pub enum Sass_OP { 79 | AND = 0, 80 | OR = 1, 81 | EQ = 2, 82 | NEQ = 3, 83 | GT = 4, 84 | GTE = 5, 85 | LT = 6, 86 | LTE = 7, 87 | ADD = 8, 88 | SUB = 9, 89 | MUL = 10, 90 | DIV = 11, 91 | MOD = 12, 92 | NUM_OPS = 13, 93 | } 94 | extern "C" { 95 | pub fn sass_make_null() -> *mut Sass_Value; 96 | } 97 | extern "C" { 98 | pub fn sass_make_boolean(val: bool) -> *mut Sass_Value; 99 | } 100 | extern "C" { 101 | pub fn sass_make_string(val: *const ::std::os::raw::c_char) -> *mut Sass_Value; 102 | } 103 | extern "C" { 104 | pub fn sass_make_qstring(val: *const ::std::os::raw::c_char) -> *mut Sass_Value; 105 | } 106 | extern "C" { 107 | pub fn sass_make_number(val: f64, unit: *const ::std::os::raw::c_char) -> *mut Sass_Value; 108 | } 109 | extern "C" { 110 | pub fn sass_make_color(r: f64, g: f64, b: f64, a: f64) -> *mut Sass_Value; 111 | } 112 | extern "C" { 113 | pub fn sass_make_list(len: usize, sep: Sass_Separator, is_bracketed: bool) -> *mut Sass_Value; 114 | } 115 | extern "C" { 116 | pub fn sass_make_map(len: usize) -> *mut Sass_Value; 117 | } 118 | extern "C" { 119 | pub fn sass_make_error(msg: *const ::std::os::raw::c_char) -> *mut Sass_Value; 120 | } 121 | extern "C" { 122 | pub fn sass_make_warning(msg: *const ::std::os::raw::c_char) -> *mut Sass_Value; 123 | } 124 | extern "C" { 125 | pub fn sass_delete_value(val: *mut Sass_Value); 126 | } 127 | extern "C" { 128 | pub fn sass_clone_value(val: *const Sass_Value) -> *mut Sass_Value; 129 | } 130 | extern "C" { 131 | pub fn sass_value_op( 132 | op: Sass_OP, 133 | a: *const Sass_Value, 134 | b: *const Sass_Value, 135 | ) -> *mut Sass_Value; 136 | } 137 | extern "C" { 138 | pub fn sass_value_stringify( 139 | a: *const Sass_Value, 140 | compressed: bool, 141 | precision: ::std::os::raw::c_int, 142 | ) -> *mut Sass_Value; 143 | } 144 | extern "C" { 145 | pub fn sass_value_get_tag(v: *const Sass_Value) -> Sass_Tag; 146 | } 147 | extern "C" { 148 | pub fn sass_value_is_null(v: *const Sass_Value) -> bool; 149 | } 150 | extern "C" { 151 | pub fn sass_value_is_number(v: *const Sass_Value) -> bool; 152 | } 153 | extern "C" { 154 | pub fn sass_value_is_string(v: *const Sass_Value) -> bool; 155 | } 156 | extern "C" { 157 | pub fn sass_value_is_boolean(v: *const Sass_Value) -> bool; 158 | } 159 | extern "C" { 160 | pub fn sass_value_is_color(v: *const Sass_Value) -> bool; 161 | } 162 | extern "C" { 163 | pub fn sass_value_is_list(v: *const Sass_Value) -> bool; 164 | } 165 | extern "C" { 166 | pub fn sass_value_is_map(v: *const Sass_Value) -> bool; 167 | } 168 | extern "C" { 169 | pub fn sass_value_is_error(v: *const Sass_Value) -> bool; 170 | } 171 | extern "C" { 172 | pub fn sass_value_is_warning(v: *const Sass_Value) -> bool; 173 | } 174 | extern "C" { 175 | pub fn sass_number_get_value(v: *const Sass_Value) -> f64; 176 | } 177 | extern "C" { 178 | pub fn sass_number_set_value(v: *mut Sass_Value, value: f64); 179 | } 180 | extern "C" { 181 | pub fn sass_number_get_unit(v: *const Sass_Value) -> *const ::std::os::raw::c_char; 182 | } 183 | extern "C" { 184 | pub fn sass_number_set_unit(v: *mut Sass_Value, unit: *mut ::std::os::raw::c_char); 185 | } 186 | extern "C" { 187 | pub fn sass_string_get_value(v: *const Sass_Value) -> *const ::std::os::raw::c_char; 188 | } 189 | extern "C" { 190 | pub fn sass_string_set_value(v: *mut Sass_Value, value: *mut ::std::os::raw::c_char); 191 | } 192 | extern "C" { 193 | pub fn sass_string_is_quoted(v: *const Sass_Value) -> bool; 194 | } 195 | extern "C" { 196 | pub fn sass_string_set_quoted(v: *mut Sass_Value, quoted: bool); 197 | } 198 | extern "C" { 199 | pub fn sass_boolean_get_value(v: *const Sass_Value) -> bool; 200 | } 201 | extern "C" { 202 | pub fn sass_boolean_set_value(v: *mut Sass_Value, value: bool); 203 | } 204 | extern "C" { 205 | pub fn sass_color_get_r(v: *const Sass_Value) -> f64; 206 | } 207 | extern "C" { 208 | pub fn sass_color_set_r(v: *mut Sass_Value, r: f64); 209 | } 210 | extern "C" { 211 | pub fn sass_color_get_g(v: *const Sass_Value) -> f64; 212 | } 213 | extern "C" { 214 | pub fn sass_color_set_g(v: *mut Sass_Value, g: f64); 215 | } 216 | extern "C" { 217 | pub fn sass_color_get_b(v: *const Sass_Value) -> f64; 218 | } 219 | extern "C" { 220 | pub fn sass_color_set_b(v: *mut Sass_Value, b: f64); 221 | } 222 | extern "C" { 223 | pub fn sass_color_get_a(v: *const Sass_Value) -> f64; 224 | } 225 | extern "C" { 226 | pub fn sass_color_set_a(v: *mut Sass_Value, a: f64); 227 | } 228 | extern "C" { 229 | pub fn sass_list_get_length(v: *const Sass_Value) -> usize; 230 | } 231 | extern "C" { 232 | pub fn sass_list_get_separator(v: *const Sass_Value) -> Sass_Separator; 233 | } 234 | extern "C" { 235 | pub fn sass_list_set_separator(v: *mut Sass_Value, value: Sass_Separator); 236 | } 237 | extern "C" { 238 | pub fn sass_list_get_is_bracketed(v: *const Sass_Value) -> bool; 239 | } 240 | extern "C" { 241 | pub fn sass_list_set_is_bracketed(v: *mut Sass_Value, value: bool); 242 | } 243 | extern "C" { 244 | pub fn sass_list_get_value(v: *const Sass_Value, i: usize) -> *mut Sass_Value; 245 | } 246 | extern "C" { 247 | pub fn sass_list_set_value(v: *mut Sass_Value, i: usize, value: *mut Sass_Value); 248 | } 249 | extern "C" { 250 | pub fn sass_map_get_length(v: *const Sass_Value) -> usize; 251 | } 252 | extern "C" { 253 | pub fn sass_map_get_key(v: *const Sass_Value, i: usize) -> *mut Sass_Value; 254 | } 255 | extern "C" { 256 | pub fn sass_map_set_key(v: *mut Sass_Value, i: usize, arg1: *mut Sass_Value); 257 | } 258 | extern "C" { 259 | pub fn sass_map_get_value(v: *const Sass_Value, i: usize) -> *mut Sass_Value; 260 | } 261 | extern "C" { 262 | pub fn sass_map_set_value(v: *mut Sass_Value, i: usize, arg1: *mut Sass_Value); 263 | } 264 | extern "C" { 265 | pub fn sass_error_get_message(v: *const Sass_Value) -> *mut ::std::os::raw::c_char; 266 | } 267 | extern "C" { 268 | pub fn sass_error_set_message(v: *mut Sass_Value, msg: *mut ::std::os::raw::c_char); 269 | } 270 | extern "C" { 271 | pub fn sass_warning_get_message(v: *const Sass_Value) -> *mut ::std::os::raw::c_char; 272 | } 273 | extern "C" { 274 | pub fn sass_warning_set_message(v: *mut Sass_Value, msg: *mut ::std::os::raw::c_char); 275 | } 276 | #[repr(C)] 277 | #[derive(Debug, Copy, Clone)] 278 | pub struct Sass_Env { 279 | _unused: [u8; 0], 280 | } 281 | #[repr(C)] 282 | #[derive(Debug, Copy, Clone)] 283 | pub struct Sass_Callee { 284 | _unused: [u8; 0], 285 | } 286 | #[repr(C)] 287 | #[derive(Debug, Copy, Clone)] 288 | pub struct Sass_Import { 289 | _unused: [u8; 0], 290 | } 291 | #[repr(C)] 292 | #[derive(Debug, Copy, Clone)] 293 | pub struct Sass_Options { 294 | _unused: [u8; 0], 295 | } 296 | #[repr(C)] 297 | #[derive(Debug, Copy, Clone)] 298 | pub struct Sass_Compiler { 299 | _unused: [u8; 0], 300 | } 301 | #[repr(C)] 302 | #[derive(Debug, Copy, Clone)] 303 | pub struct Sass_Importer { 304 | _unused: [u8; 0], 305 | } 306 | #[repr(C)] 307 | #[derive(Debug, Copy, Clone)] 308 | pub struct Sass_Function { 309 | _unused: [u8; 0], 310 | } 311 | pub type Sass_Env_Frame = *mut Sass_Env; 312 | pub type Sass_Callee_Entry = *mut Sass_Callee; 313 | pub type Sass_Import_Entry = *mut Sass_Import; 314 | pub type Sass_Import_List = *mut *mut Sass_Import; 315 | pub type Sass_Importer_Entry = *mut Sass_Importer; 316 | pub type Sass_Importer_List = *mut *mut Sass_Importer; 317 | pub type Sass_Importer_Fn = ::std::option::Option< 318 | unsafe extern "C" fn( 319 | url: *const ::std::os::raw::c_char, 320 | cb: Sass_Importer_Entry, 321 | compiler: *mut Sass_Compiler, 322 | ) -> Sass_Import_List, 323 | >; 324 | pub type Sass_Function_Entry = *mut Sass_Function; 325 | pub type Sass_Function_List = *mut *mut Sass_Function; 326 | pub type Sass_Function_Fn = ::std::option::Option< 327 | unsafe extern "C" fn( 328 | arg1: *const Sass_Value, 329 | cb: Sass_Function_Entry, 330 | compiler: *mut Sass_Compiler, 331 | ) -> *mut Sass_Value, 332 | >; 333 | #[repr(u32)] 334 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 335 | pub enum Sass_Callee_Type { 336 | SASS_CALLEE_MIXIN = 0, 337 | SASS_CALLEE_FUNCTION = 1, 338 | SASS_CALLEE_C_FUNCTION = 2, 339 | } 340 | extern "C" { 341 | pub fn sass_make_importer_list(length: usize) -> Sass_Importer_List; 342 | } 343 | extern "C" { 344 | pub fn sass_importer_get_list_entry( 345 | list: Sass_Importer_List, 346 | idx: usize, 347 | ) -> Sass_Importer_Entry; 348 | } 349 | extern "C" { 350 | pub fn sass_importer_set_list_entry( 351 | list: Sass_Importer_List, 352 | idx: usize, 353 | entry: Sass_Importer_Entry, 354 | ); 355 | } 356 | extern "C" { 357 | pub fn sass_delete_importer_list(list: Sass_Importer_List); 358 | } 359 | extern "C" { 360 | pub fn sass_make_importer( 361 | importer: Sass_Importer_Fn, 362 | priority: f64, 363 | cookie: *mut ::std::os::raw::c_void, 364 | ) -> Sass_Importer_Entry; 365 | } 366 | extern "C" { 367 | pub fn sass_importer_get_function(cb: Sass_Importer_Entry) -> Sass_Importer_Fn; 368 | } 369 | extern "C" { 370 | pub fn sass_importer_get_priority(cb: Sass_Importer_Entry) -> f64; 371 | } 372 | extern "C" { 373 | pub fn sass_importer_get_cookie(cb: Sass_Importer_Entry) -> *mut ::std::os::raw::c_void; 374 | } 375 | extern "C" { 376 | pub fn sass_delete_importer(cb: Sass_Importer_Entry); 377 | } 378 | extern "C" { 379 | pub fn sass_make_import_list(length: usize) -> Sass_Import_List; 380 | } 381 | extern "C" { 382 | pub fn sass_make_import_entry( 383 | path: *const ::std::os::raw::c_char, 384 | source: *mut ::std::os::raw::c_char, 385 | srcmap: *mut ::std::os::raw::c_char, 386 | ) -> Sass_Import_Entry; 387 | } 388 | extern "C" { 389 | pub fn sass_make_import( 390 | imp_path: *const ::std::os::raw::c_char, 391 | abs_base: *const ::std::os::raw::c_char, 392 | source: *mut ::std::os::raw::c_char, 393 | srcmap: *mut ::std::os::raw::c_char, 394 | ) -> Sass_Import_Entry; 395 | } 396 | extern "C" { 397 | pub fn sass_import_set_error( 398 | import: Sass_Import_Entry, 399 | message: *const ::std::os::raw::c_char, 400 | line: usize, 401 | col: usize, 402 | ) -> Sass_Import_Entry; 403 | } 404 | extern "C" { 405 | pub fn sass_import_set_list_entry(list: Sass_Import_List, idx: usize, entry: Sass_Import_Entry); 406 | } 407 | extern "C" { 408 | pub fn sass_import_get_list_entry(list: Sass_Import_List, idx: usize) -> Sass_Import_Entry; 409 | } 410 | extern "C" { 411 | pub fn sass_callee_get_name(arg1: Sass_Callee_Entry) -> *const ::std::os::raw::c_char; 412 | } 413 | extern "C" { 414 | pub fn sass_callee_get_path(arg1: Sass_Callee_Entry) -> *const ::std::os::raw::c_char; 415 | } 416 | extern "C" { 417 | pub fn sass_callee_get_line(arg1: Sass_Callee_Entry) -> usize; 418 | } 419 | extern "C" { 420 | pub fn sass_callee_get_column(arg1: Sass_Callee_Entry) -> usize; 421 | } 422 | extern "C" { 423 | pub fn sass_callee_get_type(arg1: Sass_Callee_Entry) -> Sass_Callee_Type; 424 | } 425 | extern "C" { 426 | pub fn sass_callee_get_env(arg1: Sass_Callee_Entry) -> Sass_Env_Frame; 427 | } 428 | extern "C" { 429 | pub fn sass_env_get_lexical( 430 | arg1: Sass_Env_Frame, 431 | arg2: *const ::std::os::raw::c_char, 432 | ) -> *mut Sass_Value; 433 | } 434 | extern "C" { 435 | pub fn sass_env_set_lexical( 436 | arg1: Sass_Env_Frame, 437 | arg2: *const ::std::os::raw::c_char, 438 | arg3: *mut Sass_Value, 439 | ); 440 | } 441 | extern "C" { 442 | pub fn sass_env_get_local( 443 | arg1: Sass_Env_Frame, 444 | arg2: *const ::std::os::raw::c_char, 445 | ) -> *mut Sass_Value; 446 | } 447 | extern "C" { 448 | pub fn sass_env_set_local( 449 | arg1: Sass_Env_Frame, 450 | arg2: *const ::std::os::raw::c_char, 451 | arg3: *mut Sass_Value, 452 | ); 453 | } 454 | extern "C" { 455 | pub fn sass_env_get_global( 456 | arg1: Sass_Env_Frame, 457 | arg2: *const ::std::os::raw::c_char, 458 | ) -> *mut Sass_Value; 459 | } 460 | extern "C" { 461 | pub fn sass_env_set_global( 462 | arg1: Sass_Env_Frame, 463 | arg2: *const ::std::os::raw::c_char, 464 | arg3: *mut Sass_Value, 465 | ); 466 | } 467 | extern "C" { 468 | pub fn sass_import_get_imp_path(arg1: Sass_Import_Entry) -> *const ::std::os::raw::c_char; 469 | } 470 | extern "C" { 471 | pub fn sass_import_get_abs_path(arg1: Sass_Import_Entry) -> *const ::std::os::raw::c_char; 472 | } 473 | extern "C" { 474 | pub fn sass_import_get_source(arg1: Sass_Import_Entry) -> *const ::std::os::raw::c_char; 475 | } 476 | extern "C" { 477 | pub fn sass_import_get_srcmap(arg1: Sass_Import_Entry) -> *const ::std::os::raw::c_char; 478 | } 479 | extern "C" { 480 | pub fn sass_import_take_source(arg1: Sass_Import_Entry) -> *mut ::std::os::raw::c_char; 481 | } 482 | extern "C" { 483 | pub fn sass_import_take_srcmap(arg1: Sass_Import_Entry) -> *mut ::std::os::raw::c_char; 484 | } 485 | extern "C" { 486 | pub fn sass_import_get_error_line(arg1: Sass_Import_Entry) -> usize; 487 | } 488 | extern "C" { 489 | pub fn sass_import_get_error_column(arg1: Sass_Import_Entry) -> usize; 490 | } 491 | extern "C" { 492 | pub fn sass_import_get_error_message(arg1: Sass_Import_Entry) -> *const ::std::os::raw::c_char; 493 | } 494 | extern "C" { 495 | pub fn sass_delete_import_list(arg1: Sass_Import_List); 496 | } 497 | extern "C" { 498 | pub fn sass_delete_import(arg1: Sass_Import_Entry); 499 | } 500 | extern "C" { 501 | pub fn sass_make_function_list(length: usize) -> Sass_Function_List; 502 | } 503 | extern "C" { 504 | pub fn sass_make_function( 505 | signature: *const ::std::os::raw::c_char, 506 | cb: Sass_Function_Fn, 507 | cookie: *mut ::std::os::raw::c_void, 508 | ) -> Sass_Function_Entry; 509 | } 510 | extern "C" { 511 | pub fn sass_delete_function(entry: Sass_Function_Entry); 512 | } 513 | extern "C" { 514 | pub fn sass_delete_function_list(list: Sass_Function_List); 515 | } 516 | extern "C" { 517 | pub fn sass_function_get_list_entry( 518 | list: Sass_Function_List, 519 | pos: usize, 520 | ) -> Sass_Function_Entry; 521 | } 522 | extern "C" { 523 | pub fn sass_function_set_list_entry( 524 | list: Sass_Function_List, 525 | pos: usize, 526 | cb: Sass_Function_Entry, 527 | ); 528 | } 529 | extern "C" { 530 | pub fn sass_function_get_signature(cb: Sass_Function_Entry) -> *const ::std::os::raw::c_char; 531 | } 532 | extern "C" { 533 | pub fn sass_function_get_function(cb: Sass_Function_Entry) -> Sass_Function_Fn; 534 | } 535 | extern "C" { 536 | pub fn sass_function_get_cookie(cb: Sass_Function_Entry) -> *mut ::std::os::raw::c_void; 537 | } 538 | #[repr(C)] 539 | #[derive(Debug, Copy, Clone)] 540 | pub struct Sass_Context { 541 | _unused: [u8; 0], 542 | } 543 | #[repr(C)] 544 | #[derive(Debug, Copy, Clone)] 545 | pub struct Sass_File_Context { 546 | _unused: [u8; 0], 547 | } 548 | #[repr(C)] 549 | #[derive(Debug, Copy, Clone)] 550 | pub struct Sass_Data_Context { 551 | _unused: [u8; 0], 552 | } 553 | #[repr(u32)] 554 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 555 | pub enum Sass_Compiler_State { 556 | SASS_COMPILER_CREATED = 0, 557 | SASS_COMPILER_PARSED = 1, 558 | SASS_COMPILER_EXECUTED = 2, 559 | } 560 | extern "C" { 561 | pub fn sass_make_options() -> *mut Sass_Options; 562 | } 563 | extern "C" { 564 | pub fn sass_make_file_context( 565 | input_path: *const ::std::os::raw::c_char, 566 | ) -> *mut Sass_File_Context; 567 | } 568 | extern "C" { 569 | pub fn sass_make_data_context( 570 | source_string: *mut ::std::os::raw::c_char, 571 | ) -> *mut Sass_Data_Context; 572 | } 573 | extern "C" { 574 | pub fn sass_compile_file_context(ctx: *mut Sass_File_Context) -> ::std::os::raw::c_int; 575 | } 576 | extern "C" { 577 | pub fn sass_compile_data_context(ctx: *mut Sass_Data_Context) -> ::std::os::raw::c_int; 578 | } 579 | extern "C" { 580 | pub fn sass_make_file_compiler(file_ctx: *mut Sass_File_Context) -> *mut Sass_Compiler; 581 | } 582 | extern "C" { 583 | pub fn sass_make_data_compiler(data_ctx: *mut Sass_Data_Context) -> *mut Sass_Compiler; 584 | } 585 | extern "C" { 586 | pub fn sass_compiler_parse(compiler: *mut Sass_Compiler) -> ::std::os::raw::c_int; 587 | } 588 | extern "C" { 589 | pub fn sass_compiler_execute(compiler: *mut Sass_Compiler) -> ::std::os::raw::c_int; 590 | } 591 | extern "C" { 592 | pub fn sass_delete_compiler(compiler: *mut Sass_Compiler); 593 | } 594 | extern "C" { 595 | pub fn sass_delete_options(options: *mut Sass_Options); 596 | } 597 | extern "C" { 598 | pub fn sass_delete_file_context(ctx: *mut Sass_File_Context); 599 | } 600 | extern "C" { 601 | pub fn sass_delete_data_context(ctx: *mut Sass_Data_Context); 602 | } 603 | extern "C" { 604 | pub fn sass_file_context_get_context(file_ctx: *mut Sass_File_Context) -> *mut Sass_Context; 605 | } 606 | extern "C" { 607 | pub fn sass_data_context_get_context(data_ctx: *mut Sass_Data_Context) -> *mut Sass_Context; 608 | } 609 | extern "C" { 610 | pub fn sass_context_get_options(ctx: *mut Sass_Context) -> *mut Sass_Options; 611 | } 612 | extern "C" { 613 | pub fn sass_file_context_get_options(file_ctx: *mut Sass_File_Context) -> *mut Sass_Options; 614 | } 615 | extern "C" { 616 | pub fn sass_data_context_get_options(data_ctx: *mut Sass_Data_Context) -> *mut Sass_Options; 617 | } 618 | extern "C" { 619 | pub fn sass_file_context_set_options(file_ctx: *mut Sass_File_Context, opt: *mut Sass_Options); 620 | } 621 | extern "C" { 622 | pub fn sass_data_context_set_options(data_ctx: *mut Sass_Data_Context, opt: *mut Sass_Options); 623 | } 624 | extern "C" { 625 | pub fn sass_option_get_precision(options: *mut Sass_Options) -> ::std::os::raw::c_int; 626 | } 627 | extern "C" { 628 | pub fn sass_option_get_output_style(options: *mut Sass_Options) -> Sass_Output_Style; 629 | } 630 | extern "C" { 631 | pub fn sass_option_get_source_comments(options: *mut Sass_Options) -> bool; 632 | } 633 | extern "C" { 634 | pub fn sass_option_get_source_map_embed(options: *mut Sass_Options) -> bool; 635 | } 636 | extern "C" { 637 | pub fn sass_option_get_source_map_contents(options: *mut Sass_Options) -> bool; 638 | } 639 | extern "C" { 640 | pub fn sass_option_get_source_map_file_urls(options: *mut Sass_Options) -> bool; 641 | } 642 | extern "C" { 643 | pub fn sass_option_get_omit_source_map_url(options: *mut Sass_Options) -> bool; 644 | } 645 | extern "C" { 646 | pub fn sass_option_get_is_indented_syntax_src(options: *mut Sass_Options) -> bool; 647 | } 648 | extern "C" { 649 | pub fn sass_option_get_indent(options: *mut Sass_Options) -> *const ::std::os::raw::c_char; 650 | } 651 | extern "C" { 652 | pub fn sass_option_get_linefeed(options: *mut Sass_Options) -> *const ::std::os::raw::c_char; 653 | } 654 | extern "C" { 655 | pub fn sass_option_get_input_path(options: *mut Sass_Options) -> *const ::std::os::raw::c_char; 656 | } 657 | extern "C" { 658 | pub fn sass_option_get_output_path(options: *mut Sass_Options) 659 | -> *const ::std::os::raw::c_char; 660 | } 661 | extern "C" { 662 | pub fn sass_option_get_source_map_file( 663 | options: *mut Sass_Options, 664 | ) -> *const ::std::os::raw::c_char; 665 | } 666 | extern "C" { 667 | pub fn sass_option_get_source_map_root( 668 | options: *mut Sass_Options, 669 | ) -> *const ::std::os::raw::c_char; 670 | } 671 | extern "C" { 672 | pub fn sass_option_get_c_headers(options: *mut Sass_Options) -> Sass_Importer_List; 673 | } 674 | extern "C" { 675 | pub fn sass_option_get_c_importers(options: *mut Sass_Options) -> Sass_Importer_List; 676 | } 677 | extern "C" { 678 | pub fn sass_option_get_c_functions(options: *mut Sass_Options) -> Sass_Function_List; 679 | } 680 | extern "C" { 681 | pub fn sass_option_set_precision(options: *mut Sass_Options, precision: ::std::os::raw::c_int); 682 | } 683 | extern "C" { 684 | pub fn sass_option_set_output_style( 685 | options: *mut Sass_Options, 686 | output_style: Sass_Output_Style, 687 | ); 688 | } 689 | extern "C" { 690 | pub fn sass_option_set_source_comments(options: *mut Sass_Options, source_comments: bool); 691 | } 692 | extern "C" { 693 | pub fn sass_option_set_source_map_embed(options: *mut Sass_Options, source_map_embed: bool); 694 | } 695 | extern "C" { 696 | pub fn sass_option_set_source_map_contents( 697 | options: *mut Sass_Options, 698 | source_map_contents: bool, 699 | ); 700 | } 701 | extern "C" { 702 | pub fn sass_option_set_source_map_file_urls( 703 | options: *mut Sass_Options, 704 | source_map_file_urls: bool, 705 | ); 706 | } 707 | extern "C" { 708 | pub fn sass_option_set_omit_source_map_url( 709 | options: *mut Sass_Options, 710 | omit_source_map_url: bool, 711 | ); 712 | } 713 | extern "C" { 714 | pub fn sass_option_set_is_indented_syntax_src( 715 | options: *mut Sass_Options, 716 | is_indented_syntax_src: bool, 717 | ); 718 | } 719 | extern "C" { 720 | pub fn sass_option_set_indent( 721 | options: *mut Sass_Options, 722 | indent: *const ::std::os::raw::c_char, 723 | ); 724 | } 725 | extern "C" { 726 | pub fn sass_option_set_linefeed( 727 | options: *mut Sass_Options, 728 | linefeed: *const ::std::os::raw::c_char, 729 | ); 730 | } 731 | extern "C" { 732 | pub fn sass_option_set_input_path( 733 | options: *mut Sass_Options, 734 | input_path: *const ::std::os::raw::c_char, 735 | ); 736 | } 737 | extern "C" { 738 | pub fn sass_option_set_output_path( 739 | options: *mut Sass_Options, 740 | output_path: *const ::std::os::raw::c_char, 741 | ); 742 | } 743 | extern "C" { 744 | pub fn sass_option_set_plugin_path( 745 | options: *mut Sass_Options, 746 | plugin_path: *const ::std::os::raw::c_char, 747 | ); 748 | } 749 | extern "C" { 750 | pub fn sass_option_set_include_path( 751 | options: *mut Sass_Options, 752 | include_path: *const ::std::os::raw::c_char, 753 | ); 754 | } 755 | extern "C" { 756 | pub fn sass_option_set_source_map_file( 757 | options: *mut Sass_Options, 758 | source_map_file: *const ::std::os::raw::c_char, 759 | ); 760 | } 761 | extern "C" { 762 | pub fn sass_option_set_source_map_root( 763 | options: *mut Sass_Options, 764 | source_map_root: *const ::std::os::raw::c_char, 765 | ); 766 | } 767 | extern "C" { 768 | pub fn sass_option_set_c_headers(options: *mut Sass_Options, c_headers: Sass_Importer_List); 769 | } 770 | extern "C" { 771 | pub fn sass_option_set_c_importers(options: *mut Sass_Options, c_importers: Sass_Importer_List); 772 | } 773 | extern "C" { 774 | pub fn sass_option_set_c_functions(options: *mut Sass_Options, c_functions: Sass_Function_List); 775 | } 776 | extern "C" { 777 | pub fn sass_context_get_output_string(ctx: *mut Sass_Context) -> *const ::std::os::raw::c_char; 778 | } 779 | extern "C" { 780 | pub fn sass_context_get_error_status(ctx: *mut Sass_Context) -> ::std::os::raw::c_int; 781 | } 782 | extern "C" { 783 | pub fn sass_context_get_error_json(ctx: *mut Sass_Context) -> *const ::std::os::raw::c_char; 784 | } 785 | extern "C" { 786 | pub fn sass_context_get_error_text(ctx: *mut Sass_Context) -> *const ::std::os::raw::c_char; 787 | } 788 | extern "C" { 789 | pub fn sass_context_get_error_message(ctx: *mut Sass_Context) -> *const ::std::os::raw::c_char; 790 | } 791 | extern "C" { 792 | pub fn sass_context_get_error_file(ctx: *mut Sass_Context) -> *const ::std::os::raw::c_char; 793 | } 794 | extern "C" { 795 | pub fn sass_context_get_error_src(ctx: *mut Sass_Context) -> *const ::std::os::raw::c_char; 796 | } 797 | extern "C" { 798 | pub fn sass_context_get_error_line(ctx: *mut Sass_Context) -> usize; 799 | } 800 | extern "C" { 801 | pub fn sass_context_get_error_column(ctx: *mut Sass_Context) -> usize; 802 | } 803 | extern "C" { 804 | pub fn sass_context_get_source_map_string( 805 | ctx: *mut Sass_Context, 806 | ) -> *const ::std::os::raw::c_char; 807 | } 808 | extern "C" { 809 | pub fn sass_context_get_included_files( 810 | ctx: *mut Sass_Context, 811 | ) -> *mut *mut ::std::os::raw::c_char; 812 | } 813 | extern "C" { 814 | pub fn sass_option_get_include_path_size(options: *mut Sass_Options) -> usize; 815 | } 816 | extern "C" { 817 | pub fn sass_option_get_include_path( 818 | options: *mut Sass_Options, 819 | i: usize, 820 | ) -> *const ::std::os::raw::c_char; 821 | } 822 | extern "C" { 823 | pub fn sass_context_get_included_files_size(ctx: *mut Sass_Context) -> usize; 824 | } 825 | extern "C" { 826 | pub fn sass_context_take_error_json(ctx: *mut Sass_Context) -> *mut ::std::os::raw::c_char; 827 | } 828 | extern "C" { 829 | pub fn sass_context_take_error_text(ctx: *mut Sass_Context) -> *mut ::std::os::raw::c_char; 830 | } 831 | extern "C" { 832 | pub fn sass_context_take_error_message(ctx: *mut Sass_Context) -> *mut ::std::os::raw::c_char; 833 | } 834 | extern "C" { 835 | pub fn sass_context_take_error_file(ctx: *mut Sass_Context) -> *mut ::std::os::raw::c_char; 836 | } 837 | extern "C" { 838 | pub fn sass_context_take_output_string(ctx: *mut Sass_Context) -> *mut ::std::os::raw::c_char; 839 | } 840 | extern "C" { 841 | pub fn sass_context_take_source_map_string( 842 | ctx: *mut Sass_Context, 843 | ) -> *mut ::std::os::raw::c_char; 844 | } 845 | extern "C" { 846 | pub fn sass_context_take_included_files( 847 | ctx: *mut Sass_Context, 848 | ) -> *mut *mut ::std::os::raw::c_char; 849 | } 850 | extern "C" { 851 | pub fn sass_compiler_get_state(compiler: *mut Sass_Compiler) -> Sass_Compiler_State; 852 | } 853 | extern "C" { 854 | pub fn sass_compiler_get_context(compiler: *mut Sass_Compiler) -> *mut Sass_Context; 855 | } 856 | extern "C" { 857 | pub fn sass_compiler_get_options(compiler: *mut Sass_Compiler) -> *mut Sass_Options; 858 | } 859 | extern "C" { 860 | pub fn sass_compiler_get_import_stack_size(compiler: *mut Sass_Compiler) -> usize; 861 | } 862 | extern "C" { 863 | pub fn sass_compiler_get_last_import(compiler: *mut Sass_Compiler) -> Sass_Import_Entry; 864 | } 865 | extern "C" { 866 | pub fn sass_compiler_get_import_entry( 867 | compiler: *mut Sass_Compiler, 868 | idx: usize, 869 | ) -> Sass_Import_Entry; 870 | } 871 | extern "C" { 872 | pub fn sass_compiler_get_callee_stack_size(compiler: *mut Sass_Compiler) -> usize; 873 | } 874 | extern "C" { 875 | pub fn sass_compiler_get_last_callee(compiler: *mut Sass_Compiler) -> Sass_Callee_Entry; 876 | } 877 | extern "C" { 878 | pub fn sass_compiler_get_callee_entry( 879 | compiler: *mut Sass_Compiler, 880 | idx: usize, 881 | ) -> Sass_Callee_Entry; 882 | } 883 | extern "C" { 884 | pub fn sass_option_push_plugin_path( 885 | options: *mut Sass_Options, 886 | path: *const ::std::os::raw::c_char, 887 | ); 888 | } 889 | extern "C" { 890 | pub fn sass_option_push_include_path( 891 | options: *mut Sass_Options, 892 | path: *const ::std::os::raw::c_char, 893 | ); 894 | } 895 | extern "C" { 896 | pub fn sass_find_file( 897 | path: *const ::std::os::raw::c_char, 898 | opt: *mut Sass_Options, 899 | ) -> *mut ::std::os::raw::c_char; 900 | } 901 | extern "C" { 902 | pub fn sass_find_include( 903 | path: *const ::std::os::raw::c_char, 904 | opt: *mut Sass_Options, 905 | ) -> *mut ::std::os::raw::c_char; 906 | } 907 | extern "C" { 908 | pub fn sass_compiler_find_file( 909 | path: *const ::std::os::raw::c_char, 910 | compiler: *mut Sass_Compiler, 911 | ) -> *mut ::std::os::raw::c_char; 912 | } 913 | extern "C" { 914 | pub fn sass_compiler_find_include( 915 | path: *const ::std::os::raw::c_char, 916 | compiler: *mut Sass_Compiler, 917 | ) -> *mut ::std::os::raw::c_char; 918 | } 919 | extern "C" { 920 | pub fn sass2scss( 921 | sass: *const ::std::os::raw::c_char, 922 | options: ::std::os::raw::c_int, 923 | ) -> *mut ::std::os::raw::c_char; 924 | } 925 | extern "C" { 926 | pub fn sass2scss_version() -> *const ::std::os::raw::c_char; 927 | } 928 | -------------------------------------------------------------------------------- /sass-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![allow(non_upper_case_globals)] 3 | 4 | mod bindings; 5 | pub use bindings::*; 6 | -------------------------------------------------------------------------------- /src/bindings/context.rs: -------------------------------------------------------------------------------- 1 | //! Allow access to the various flavours of sass contexts: 2 | //! 3 | 4 | use std::ffi; 5 | use std::sync::{Arc, RwLock}; 6 | use std::path::Path; 7 | use libc::strdup; 8 | 9 | use sass_sys; 10 | use bindings::util; 11 | use bindings::ptr::Unique; 12 | use options::{OutputStyle, Options}; 13 | use bindings::SassOptions; 14 | 15 | 16 | pub struct SassContext { 17 | // Need Unique to send between threads, libsass is thread safe 18 | pub raw: Unique, 19 | pub options: Arc> 20 | } 21 | 22 | pub struct SassFileContext { 23 | // Need Unique to send between threads, libsass is thread safe 24 | context: Unique, 25 | pub sass_context: SassContext 26 | } 27 | 28 | pub struct SassDataContext { 29 | // Need Unique to send between threads, libsass is thread safe 30 | context: Unique, 31 | pub sass_context: SassContext 32 | } 33 | 34 | pub enum Context { 35 | File(SassFileContext), 36 | Data(SassDataContext), 37 | } 38 | 39 | 40 | impl Context { 41 | fn make_sass_context(c_sass_context: *mut sass_sys::Sass_Context) -> SassContext { 42 | let options = unsafe { sass_sys::sass_context_get_options(c_sass_context) }; 43 | let sass_options = Arc::new(RwLock::new(SassOptions { 44 | raw: unsafe { Unique::new(options) } 45 | })); 46 | 47 | SassContext { 48 | raw: unsafe { Unique::new(c_sass_context) }, 49 | options: sass_options 50 | } 51 | } 52 | 53 | pub fn new_data(data: &str) -> Context { 54 | let c_str = ffi::CString::new(data).unwrap(); 55 | let data_context = unsafe { sass_sys::sass_make_data_context(strdup(c_str.as_ptr())) }; 56 | let data_sass_context = unsafe { sass_sys::sass_data_context_get_context(data_context) }; 57 | let sass_context = Context::make_sass_context(data_sass_context); 58 | 59 | Context::Data(SassDataContext { 60 | context: unsafe { Unique::new(data_context) }, 61 | sass_context, 62 | }) 63 | } 64 | 65 | pub fn new_file>(path: P) -> Result { 66 | let c_str = ffi::CString::new( 67 | path.as_ref().to_str().ok_or_else(|| "str conversation failed".to_string())? 68 | ).map_err(|e| format!("Failed to create CString: {}", e))?; 69 | let file_context = unsafe { sass_sys::sass_make_file_context(c_str.as_ptr()) }; 70 | let file_sass_context = unsafe { sass_sys::sass_file_context_get_context(file_context) }; 71 | let sass_context = Context::make_sass_context(file_sass_context); 72 | 73 | Ok(Context::File(SassFileContext { 74 | context: unsafe { Unique::new(file_context) }, 75 | sass_context, 76 | })) 77 | } 78 | 79 | pub fn set_options(&mut self, options: Options) { 80 | let mut sass_options = match *self { 81 | Context::File(ref mut s) => { 82 | (*s.sass_context.options).write().unwrap() 83 | }, 84 | Context::Data(ref mut s) => { 85 | (*s.sass_context.options).write().unwrap() 86 | }, 87 | }; 88 | sass_options.set_output_style(options.output_style); 89 | sass_options.set_precision(options.precision); 90 | if options.indented_syntax { 91 | sass_options.set_is_indented_syntax(); 92 | } 93 | if !options.include_paths.is_empty() { 94 | sass_options.set_include_path(options.include_paths); 95 | } 96 | } 97 | 98 | pub fn compile(&mut self) -> Result { 99 | let ctx_out = match *self { 100 | Context::File(ref mut s) => unsafe { 101 | sass_sys::sass_compile_file_context(s.context.get_mut()); 102 | s.sass_context.raw.get_mut() 103 | }, 104 | Context::Data(ref mut s) => unsafe { 105 | sass_sys::sass_compile_data_context(s.context.get_mut()); 106 | s.sass_context.raw.get_mut() 107 | }, 108 | }; 109 | 110 | let error_status = unsafe { sass_sys::sass_context_get_error_status(ctx_out) }; 111 | let error_message = unsafe { sass_sys::sass_context_get_error_message(ctx_out) }; 112 | let output_string = unsafe { sass_sys::sass_context_get_output_string(ctx_out) }; 113 | 114 | if error_status != 0 { 115 | if !error_message.is_null() { 116 | Result::Err(util::to_string(error_message)) 117 | } else { 118 | Result::Err("An error occurred; no error message available.".to_string()) 119 | } 120 | } else { 121 | Result::Ok(util::to_string(output_string)) 122 | } 123 | } 124 | 125 | pub fn set_output_style(&mut self, output_style: OutputStyle) { 126 | match *self { 127 | Context::File(ref mut s) => { 128 | let mut options = (*s.sass_context.options).write().unwrap(); 129 | options.set_output_style(output_style); 130 | }, 131 | Context::Data(ref mut s) => { 132 | let mut options = (*s.sass_context.options).write().unwrap(); 133 | options.set_output_style(output_style); 134 | }, 135 | }; 136 | } 137 | } 138 | 139 | impl Drop for Context { 140 | fn drop(&mut self) { 141 | match *self { 142 | Context::File(ref mut s) => unsafe { 143 | sass_sys::sass_delete_file_context(s.context.get_mut()) 144 | }, 145 | Context::Data(ref mut s) => unsafe { 146 | sass_sys::sass_delete_data_context(s.context.get_mut()) 147 | }, 148 | }; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/bindings/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains all the unsafe code linking to sass-sys 2 | mod options; 3 | mod context; 4 | // copied from libcore for Unique<> 5 | mod ptr; 6 | mod util; 7 | 8 | pub use self::options::SassOptions; 9 | pub use self::context::Context; 10 | -------------------------------------------------------------------------------- /src/bindings/options.rs: -------------------------------------------------------------------------------- 1 | use std::ffi; 2 | 3 | use sass_sys::{self, Sass_Output_Style}; 4 | 5 | use bindings::ptr::Unique; 6 | 7 | use options::OutputStyle; 8 | 9 | /// The internal options we will pass to libsass 10 | #[derive(Debug)] 11 | pub struct SassOptions { 12 | pub raw: Unique 13 | } 14 | 15 | impl SassOptions { 16 | pub fn set_output_style(&mut self, style: OutputStyle) { 17 | let style = match style { 18 | OutputStyle::Nested => Sass_Output_Style::SASS_STYLE_NESTED, 19 | OutputStyle::Expanded => Sass_Output_Style::SASS_STYLE_EXPANDED, 20 | OutputStyle::Compact => Sass_Output_Style::SASS_STYLE_COMPACT, 21 | OutputStyle::Compressed => Sass_Output_Style::SASS_STYLE_COMPRESSED, 22 | }; 23 | 24 | unsafe { 25 | sass_sys::sass_option_set_output_style(self.raw.get_mut(), style); 26 | } 27 | } 28 | 29 | pub fn set_precision(&mut self, precision: usize) { 30 | unsafe { 31 | sass_sys::sass_option_set_precision(self.raw.get_mut(), precision as i32); 32 | } 33 | } 34 | 35 | pub fn set_is_indented_syntax(&mut self) { 36 | unsafe { 37 | sass_sys::sass_option_set_is_indented_syntax_src(self.raw.get_mut(), true); 38 | } 39 | } 40 | 41 | pub fn set_include_path(&mut self, paths: Vec) { 42 | let include_path = if cfg!(windows) { 43 | paths.join(";") 44 | } else { 45 | paths.join(":") 46 | }; 47 | let c_str = ffi::CString::new(include_path).unwrap(); 48 | let ptr = c_str.into_raw(); 49 | unsafe { 50 | sass_sys::sass_option_set_include_path(self.raw.get_mut(), ptr); 51 | let _ = ffi::CString::from_raw(ptr); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/bindings/ptr.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT 3 | // file at the top-level directory of this distribution and at 4 | // http://rust-lang.org/COPYRIGHT. 5 | // 6 | // Licensed under the Apache License, Version 2.0 or the MIT license 8 | // , at your 9 | // option. This file may not be copied, modified, or distributed 10 | // except according to those terms. 11 | 12 | 13 | use std::marker::{PhantomData, Send, Sized, Sync}; 14 | 15 | 16 | /// A wrapper around a raw `*mut T` that indicates that the possessor 17 | /// of this wrapper owns the referent. This in turn implies that the 18 | /// `Unique` is `Send`/`Sync` if `T` is `Send`/`Sync`, unlike a raw 19 | /// `*mut T` (which conveys no particular ownership semantics). It 20 | /// also implies that the referent of the pointer should not be 21 | /// modified without a unique path to the `Unique` reference. Useful 22 | /// for building abstractions like `Vec` or `Box`, which 23 | /// internally use raw pointers to manage the memory that they own. 24 | #[derive(Debug)] 25 | pub struct Unique { 26 | pointer: *mut T, 27 | _marker: PhantomData, 28 | } 29 | 30 | /// `Unique` pointers are `Send` if `T` is `Send` because the data they 31 | /// reference is unaliased. Note that this aliasing invariant is 32 | /// unenforced by the type system; the abstraction using the 33 | /// `Unique` must enforce it. 34 | unsafe impl Send for Unique {} 35 | 36 | /// `Unique` pointers are `Sync` if `T` is `Sync` because the data they 37 | /// reference is unaliased. Note that this aliasing invariant is 38 | /// unenforced by the type system; the abstraction using the 39 | /// `Unique` must enforce it. 40 | unsafe impl Sync for Unique {} 41 | 42 | impl Unique { 43 | /// Creates a new `Unique`. 44 | pub unsafe fn new(ptr: *mut T) -> Unique { 45 | Unique { pointer: ptr, _marker: PhantomData } 46 | } 47 | 48 | /// Dereferences the content. 49 | pub unsafe fn get(&self) -> &T { 50 | &*self.pointer 51 | } 52 | 53 | /// Mutably dereferences the content. 54 | pub unsafe fn get_mut(&mut self) -> &mut T { 55 | //&mut ***self 56 | &mut *self.pointer 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/bindings/util.rs: -------------------------------------------------------------------------------- 1 | use libc::c_char; 2 | use std::ffi::CStr; 3 | 4 | 5 | pub fn to_string(c_buf: *const c_char) -> String { 6 | unsafe { CStr::from_ptr(c_buf) }.to_string_lossy().into_owned() 7 | } 8 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate sass_sys; 2 | extern crate libc; 3 | 4 | mod bindings; 5 | mod options; 6 | // mod dispatcher; 7 | 8 | pub use options::{Options, OutputStyle}; 9 | pub use bindings::Context; 10 | 11 | use std::path::Path; 12 | 13 | 14 | /// Takes a file path and compiles it with the options given 15 | pub fn compile_file>(path: P, options: Options) -> Result { 16 | let mut context = Context::new_file(path)?; 17 | context.set_options(options); 18 | context.compile() 19 | } 20 | 21 | /// Takes a string and compiles it with the options given 22 | pub fn compile_string(content: &str, options: Options) -> Result { 23 | let mut context = Context::new_data(content); 24 | context.set_options(options); 25 | context.compile() 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::{Options, OutputStyle, compile_string}; 31 | 32 | #[test] 33 | fn can_compile_some_valid_scss_input() { 34 | let input = "body { .hey { color: red; } }"; 35 | assert_eq!(compile_string(input, Options::default()), 36 | Ok("body .hey {\n color: red; }\n".to_string())); 37 | } 38 | 39 | #[test] 40 | fn errors_with_invalid_scss_input() { 41 | let input = "body { .hey { color: ; } }"; 42 | let res = compile_string(input, Options::default()); 43 | assert!(res.is_err()); 44 | } 45 | 46 | #[test] 47 | fn can_use_alternative_options() { 48 | let input = "body { .hey { color: red; } }"; 49 | let mut opts = Options::default(); 50 | opts.output_style = OutputStyle::Compressed; 51 | assert_eq!(compile_string(input, opts), 52 | Ok("body .hey{color:red}\n".to_string())); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate sass_rs; 2 | 3 | use sass_rs::{compile_string, Options, OutputStyle}; 4 | use std::io::{self, Read}; 5 | 6 | fn main() { 7 | let mut buffer = String::new(); 8 | io::stdin().read_to_string(&mut buffer).unwrap(); 9 | 10 | let mut opts = Options::default(); 11 | 12 | // SCSS vs. SASS. 13 | if std::env::args().any(|i| i == "--sass") { 14 | opts.indented_syntax = true; 15 | } 16 | 17 | // Output style. 18 | if std::env::args().any(|i| i == "--expanded") { 19 | opts.output_style = OutputStyle::Expanded; 20 | } 21 | if std::env::args().any(|i| i == "--compact") { 22 | opts.output_style = OutputStyle::Compact; 23 | } 24 | if std::env::args().any(|i| i == "--compressed") { 25 | opts.output_style = OutputStyle::Compressed; 26 | } 27 | 28 | match compile_string(buffer.as_str(), opts) { 29 | Ok(sass) => println!("{}", sass), 30 | Err(e) => { 31 | println!("\nSASS/SCSS couldn't be converted bacause of the following error. Please check the input.\n"); 32 | eprintln!("{}", e); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/options.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, PartialEq)] 2 | /// See the [Sass docs](https://sass-lang.com/documentation/file.SASS_REFERENCE.html#output_style) 3 | /// for examples of how each style looks. 4 | pub enum OutputStyle { 5 | Nested, 6 | Expanded, 7 | Compact, 8 | Compressed, 9 | } 10 | 11 | /// The user facing Options struct, where they can select the libsass 12 | /// options 13 | #[derive(Debug, PartialEq, Clone)] 14 | pub struct Options { 15 | /// The output format of the final CSS style. 16 | pub output_style: OutputStyle, 17 | /// How many digits after the decimal will be allowed. 18 | pub precision: usize, 19 | /// `true` values enable Sass Indented Syntax for parsing the data string or file. 20 | pub indented_syntax: bool, 21 | /// An array of paths that LibSass can look in to attempt to resolve your @import declarations. 22 | pub include_paths: Vec, 23 | } 24 | 25 | impl Default for Options { 26 | fn default() -> Self { 27 | Options { 28 | output_style: OutputStyle::Nested, 29 | precision: 5, 30 | indented_syntax: false, 31 | include_paths: vec![], 32 | } 33 | } 34 | } 35 | --------------------------------------------------------------------------------