├── tests ├── bad.scss ├── good.scss ├── all.tcl └── sass.test ├── README ├── license.terms ├── aclocal.m4 ├── pkgIndex.tcl.in ├── generic ├── rcVersion.h ├── pkgVersion.h ├── tclsass.h ├── tclsassInt.h └── tclsass.c ├── doc ├── sass.n └── man.macros ├── README.md ├── helper.tcl ├── configure.in ├── tclconfig └── install-sh └── Makefile.in /tests/bad.scss: -------------------------------------------------------------------------------- 1 | This is not good SCSS. 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | TODO: Add real README content here. 3 | -------------------------------------------------------------------------------- /license.terms: -------------------------------------------------------------------------------- 1 | 2 | TODO: Put the real license terms in here. 3 | -------------------------------------------------------------------------------- /tests/good.scss: -------------------------------------------------------------------------------- 1 | $font-stack: Helvetica, sans-serif; 2 | $primary-color: #333; 3 | 4 | body { 5 | font: 100% $font-stack; 6 | color: $primary-color; 7 | } 8 | -------------------------------------------------------------------------------- /aclocal.m4: -------------------------------------------------------------------------------- 1 | # 2 | # Include the TEA standard macro set 3 | # 4 | 5 | builtin(include,tclconfig/tcl.m4) 6 | 7 | # 8 | # Add here whatever m4 macros you want to define for your package 9 | # 10 | -------------------------------------------------------------------------------- /pkgIndex.tcl.in: -------------------------------------------------------------------------------- 1 | # 2 | # pkgIndex.tcl -- Tcl Package for libsass 3 | # 4 | # Tcl package index file. 5 | # 6 | # Written by Joe Mistachkin. 7 | # 8 | # See the file "license.terms" for information on usage and redistribution 9 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10 | 11 | package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \ 12 | [subst -nocommands -nobackslashes { 13 | source [file join $dir helper.tcl] 14 | ::tclsass::load $dir @PKG_LIB_FILE@ @PACKAGE_NAME@ 15 | }] 16 | -------------------------------------------------------------------------------- /generic/rcVersion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rcVersion.h -- Tcl Package for libsass 3 | * 4 | * Copyright (c) 2007-2012 by Joe Mistachkin. All rights reserved. 5 | * 6 | * See the file "license.terms" for information on usage and redistribution of 7 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. 8 | * 9 | * RCS: @(#) $Id: $ 10 | */ 11 | 12 | #ifndef _RC_VERSION_H_ 13 | #define _RC_VERSION_H_ 14 | 15 | #define PACKAGE_PATCH_LEVEL 1.0.0.0 16 | #define RC_VERSION 1,0,0,0 17 | 18 | #endif /* _RC_VERSION_H_ */ 19 | -------------------------------------------------------------------------------- /tests/all.tcl: -------------------------------------------------------------------------------- 1 | # all.tcl -- 2 | # 3 | # This file contains a top-level script to run all of the Tcl 4 | # tests. Execute it by invoking "source all.test" when running tcltest 5 | # in this directory. 6 | # 7 | # Copyright (c) 1998-1999 by Scriptics Corporation. 8 | # Copyright (c) 2000 by Ajuba Solutions 9 | # 10 | # See the file "license.terms" for information on usage and redistribution 11 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 | 13 | set tcltestVersion [package require tcltest] 14 | namespace import -force tcltest::* 15 | 16 | tcltest::testsDirectory [file dir [info script]] 17 | tcltest::runAllTests 18 | 19 | return 20 | -------------------------------------------------------------------------------- /generic/pkgVersion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pkgVersion.h -- Tcl Package for libsass 3 | * 4 | * Written by Joe Mistachkin. 5 | * 6 | * See the file "license.terms" for information on usage and redistribution of 7 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. 8 | */ 9 | 10 | #ifndef _PKG_VERSION_H_ 11 | #define _PKG_VERSION_H_ 12 | 13 | // Defined on command line 14 | //#define PACKAGE_NAME "sass" 15 | #define COMMAND_NAME "sass" 16 | // Defined on command line 17 | //#define PACKAGE_VERSION "1.0" 18 | // Minimum acceptable version of Tcl - maybe change to TCL_VERSION? 19 | #define PACKAGE_TCL_VERSION "8.4" 20 | // Not used 21 | //#define SOURCE_ID "0000000000000000000000000000000000000000" 22 | //#define SOURCE_TIMESTAMP "0000-00-00 00:00:00 UTC" 23 | 24 | #endif /* _PKG_VERSION_H_ */ 25 | -------------------------------------------------------------------------------- /generic/tclsass.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tclsass.h -- Tcl Package for libsass 3 | * 4 | * Written by Joe Mistachkin. 5 | * 6 | * See the file "license.terms" for information on usage and redistribution of 7 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. 8 | */ 9 | 10 | #ifndef _TCLSASS_H_ 11 | #define _TCLSASS_H_ 12 | 13 | /* 14 | * NOTE: These are the public functions exported by this library. 15 | */ 16 | 17 | #ifndef PACKAGE_EXTERN 18 | #define PACKAGE_EXTERN 19 | #endif 20 | 21 | PACKAGE_EXTERN int Sass_Init(Tcl_Interp *interp); 22 | PACKAGE_EXTERN int Sass_SafeInit(Tcl_Interp *interp); 23 | PACKAGE_EXTERN int Sass_Unload(Tcl_Interp *interp, int flags); 24 | PACKAGE_EXTERN int Sass_SafeUnload(Tcl_Interp *interp, int flags); 25 | 26 | #endif /* _TCLSASS_H_ */ 27 | -------------------------------------------------------------------------------- /doc/sass.n: -------------------------------------------------------------------------------- 1 | '\" 2 | .so man.macros 3 | .TH sass n 1.0 "Tcl-Extensions" 4 | .HS sass tcl 5 | .BS 6 | '\" Note: do not modify the .SH NAME line immediately below! 7 | .SH NAME 8 | sass \- interfaces with Sass, a pre-processing language for CSS. 9 | .SH SYNOPSIS 10 | \fBpackage require sass\fR ?\fB1.0\fR? 11 | .sp 12 | \fBsass\fR \fBcompile \fR?\fB\-type\fR \fItype\fR? \fR?\fB\-options\fR \fIdictionary\fR? ?\fB\-\|\-\fR? ?\fIsource\fR? 13 | .sp 14 | \fBsass version\fR 15 | .BE 16 | .SH DESCRIPTION 17 | .PP 18 | This command is used to compile Sass language source into CSS via libsass. The 19 | \fItype\fR value must be \fBdata\fR or \fBfile\fR. The \fIdictionary\fR value 20 | must be a dictionary containing name/value pairs that correspond to the subset 21 | of context options supported by libsass and this package, which is: 22 | .PP 23 | .TP 24 | \fBprecision\fR 25 | .PP 26 | Integer that specifies the floating point precision. 27 | .TP 28 | \fBoutput_style\fR 29 | .PP 30 | Must be \fBnested\fR, \fBexpanded\fR, \fBcompact\fR, or \fBcompressed\fR. 31 | .TP 32 | \fBsource_comments\fR 33 | .PP 34 | Boolean to enable/disable source comments. 35 | .TP 36 | \fBsource_map_embed\fR 37 | .PP 38 | Boolean to enable/disable source map embedding. 39 | .TP 40 | \fBsource_map_contents\fR 41 | .PP 42 | Boolean to enable/disable source map contents. 43 | .TP 44 | \fBomit_source_map_url\fR 45 | .PP 46 | Boolean to omit/include source map URL. 47 | .TP 48 | \fBis_indented_syntax_src\fR 49 | .PP 50 | Boolean to enable/disable indented syntax. 51 | .TP 52 | \fBindent\fR 53 | .PP 54 | String used to indent levels in the CSS output. 55 | .TP 56 | \fBlinefeed\fR 57 | .PP 58 | String used to advance lines in the CSS output. 59 | .TP 60 | \fBinput_path\fR 61 | .PP 62 | String input path. 63 | .TP 64 | \fBoutput_path\fR 65 | .PP 66 | String output path. 67 | .TP 68 | \fBimage_path\fR 69 | .PP 70 | String image path. 71 | .TP 72 | \fBinclude_path\fR 73 | .PP 74 | String include path, delimited by PATH separator. 75 | .TP 76 | \fBsource_map_file\fR 77 | .PP 78 | String source map file name. 79 | '\" Local Variables: 80 | '\" mode: nroff 81 | '\" fill-column: 78 82 | '\" End: 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### libsass version support 2 | 3 | The libsass library has several API changes over time. The code has source dependencies on the libsass version. 4 | Check your version of the libsass library. This code should work with 3.3.x, 3.4.x and beta 3.5.x. 5 | 6 | Over time there was some mixing of C++ delete and C free in libsass API. That can corrupt the heap. The library libsass should free passed strings. But as the API evolved, there are versions that do not free all the strings passed to the API calls. This can result in memory leaks. It looks like for tclsass the libsass 3.5.x will address all this issue. The addition of sass_delete_options() will complete the memory management fixes. 7 | 8 | If you have version of libsass older than 3.3.x, then set CFLAGS=-DTCLSASS_CALLER_FREE to free strings passed to the API. THIS HAS NOT BEEN TESTED. You will have to check the behavior of your specific libsass version. 9 | 10 | ### Configuration 11 | 12 | You should be able to build with 13 | 14 | autoreconf && ./configure && make && make install 15 | 16 | If you need to adjust the paths to locate libsass, use the CFLAGS and LDFLAGS variables to pass the paths to configure. 17 | 18 | 19 | ### Building 20 | 21 | Some versions of gcc produce bad code compiling libsass. For example, 4.8.3. 22 | 23 | We have found that none of the tclsass tests will pass if libsass is compiled with -O2 but all of them will pass if it is compiled with -O1. 24 | 25 | gcc 4.8.5 works OK compiling libsass with -O2. We don't know what happens with 4.8.4. 26 | 27 | libsass is writting using features in the c++0x standard that weren't added until gcc 4.6, so if you get something about option not recognized for -std, your C++ compiler is too old. 28 | 29 | ### How to use 30 | 31 | Here is the revised spec (v3): 32 | 33 | Tcl Package Format: TEA 34 | 35 | Documentation Format: TEA 36 | 37 | Tcl Command Name: "sass" 38 | 39 | Sub-Commands: "version", "compile" 40 | 41 | The [sass version] sub-command will have no arguments. 42 | It will return the full version of libsass in use. 43 | 44 | The [sass compile] sub-command will have the following options: 45 | 46 | -type ; # "type" must be "data" or "file". 47 | -options ; # see below. 48 | 49 | The [sass compile] sub-command will either return an error -OR- 50 | the compiler output, which will be a dictionary. The possible 51 | named values within the dictionary will initially be: 52 | 53 | errorStatus; # always available, zero means success 54 | outputString; # success only 55 | sourceMapString; # success only (with source maps enabled) 56 | errorMessage; # failure only 57 | errorLine; # failure only 58 | errorColumn; # failure only 59 | 60 | For the dictionary value of -options, the following names will 61 | be supported: 62 | 63 | precision (int) 64 | output_style (enum) 65 | source_comments (bool) 66 | source_map_embed (bool) 67 | source_map_contents (bool) 68 | omit_source_map_url (bool) 69 | is_indented_syntax_src (bool) 70 | indent (string) 71 | linefeed (string) 72 | input_path (string) 73 | output_path (string) 74 | image_path (string) ... (removed by libsass, now an error) 75 | include_path (string) 76 | source_map_file (string) 77 | 78 | This above list of options is based on the libsass public 79 | interface and is subject to change in future versions. 80 | -------------------------------------------------------------------------------- /generic/tclsassInt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tclsassInt.h -- Tcl Package for libsass 3 | * 4 | * Written by Joe Mistachkin. 5 | * 6 | * See the file "license.terms" for information on usage and redistribution of 7 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. 8 | */ 9 | 10 | #ifndef _TCLSASS_INT_H_ 11 | #define _TCLSASS_INT_H_ 12 | 13 | /* 14 | * NOTE: These "printf" formats are used for trace message formatting only. 15 | */ 16 | 17 | #define PACKAGE_HEX_FMT "0x%X" 18 | #define PACKAGE_PTR_FMT "%p" 19 | 20 | /* 21 | * NOTE: The PACKAGE_TRACE macro is used to report important diagnostics when 22 | * other means are not available. Currently, this macro is enabled by 23 | * default; however, it may be overridden via the compiler command line. 24 | */ 25 | 26 | #ifndef PACKAGE_TRACE 27 | #ifdef _TRACE 28 | #define PACKAGE_TRACE(x) printf x 29 | #else 30 | #define PACKAGE_TRACE(x) 31 | #endif 32 | #endif 33 | 34 | /* 35 | * NOTE: When the package is being compiled with the PACKAGE_DEBUG option 36 | * enabled, we want to handle serious errors using either the Tcl_Panic 37 | * function from the Tcl API or the printf function from the CRT. Which 38 | * of these functions gets used depends on the build configuration. In 39 | * the "Debug" build configuration, the Tcl_Panic function is used so 40 | * that it can immediately abort the process. In the "Release" build 41 | * configuration, the printf function is used to report the error to the 42 | * standard output channel, if available. Currently, there are only two 43 | * places where this macro is used and neither of them strictly require 44 | * the process to be aborted; therefore, when the package is compiled 45 | * without the PACKAGE_DEBUG option enabled, this macro does nothing. 46 | */ 47 | 48 | #ifdef PACKAGE_DEBUG 49 | #ifdef _DEBUG 50 | #define PACKAGE_PANIC(x) Tcl_Panic x 51 | #else 52 | #define PACKAGE_PANIC(x) printf x 53 | #endif 54 | #else 55 | #define PACKAGE_PANIC(x) 56 | #endif 57 | 58 | /* 59 | * NOTE: Flag values for the _Unload callback function (Tcl 8.5+). 60 | */ 61 | 62 | #if !defined(TCL_UNLOAD_DETACH_FROM_INTERPRETER) 63 | #define TCL_UNLOAD_DETACH_FROM_INTERPRETER (1<<0) 64 | #endif 65 | 66 | #if !defined(TCL_UNLOAD_DETACH_FROM_PROCESS) 67 | #define TCL_UNLOAD_DETACH_FROM_PROCESS (1<<1) 68 | #endif 69 | 70 | /* 71 | * HACK: This flag means that the _Unload callback function is being 72 | * called from the _Init function to cleanup due to a package load 73 | * failure. This flag is NOT defined by Tcl and MUST NOT conflict with 74 | * the unloading related flags defined by Tcl in "tcl.h". 75 | */ 76 | 77 | #if !defined(TCL_UNLOAD_FROM_INIT) 78 | #define TCL_UNLOAD_FROM_INIT (1<<2) 79 | #endif 80 | 81 | /* 82 | * NOTE: This macro returns the number of elements in an array. 83 | */ 84 | 85 | #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) 86 | 87 | /* 88 | * NOTE: This macro is used to slightly simplify the option/argument checking 89 | * against various "well-known" option names and dictionary keys passed 90 | * as constant strings. 91 | */ 92 | 93 | #define CheckString(len,arg,str) \ 94 | (((len) == strlen((str))) && (strcmp((arg), (str)) == 0)) 95 | 96 | /* 97 | * NOTE: These are semi-generic function types, used for interfacing with 98 | * various functions from the Tcl C API and the Sass C API. 99 | */ 100 | 101 | typedef int (fn_get_any) (); 102 | typedef void (fn_set_any) (); 103 | 104 | #endif /* _TCLSASS_INT_H_ */ 105 | -------------------------------------------------------------------------------- /helper.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # helper.tcl -- Tcl Package for libsass 3 | # 4 | # Defines procedures used with the command(s) created by this package. 5 | # 6 | # Written by Joe Mistachkin. 7 | # 8 | # See the file "license.terms" for information on usage and redistribution 9 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10 | 11 | namespace eval ::tclsass { 12 | # 13 | # NOTE: The syntax error message for the [compileWithSass] procedure. It is 14 | # used in several places. 15 | # 16 | variable compileSyntax \ 17 | "wrong # args: should be \"compileWithSass ?options? source\"" 18 | 19 | # 20 | # NOTE: This procedure wraps the [sass compile] sub-command. The purpose of 21 | # it is to add an "input_path" option if the input type is "file". It 22 | # should be noted that this procedure will NOT override a pre-existing 23 | # "input_path" option. 24 | # 25 | proc compileWithSass { args } { 26 | variable compileSyntax 27 | 28 | # 29 | # NOTE: Since the [sass compile] sub-command requires at least one 30 | # argument, having none is a syntax error. 31 | # 32 | if {[llength $args] == 0} then { 33 | error $compileSyntax 34 | } 35 | 36 | # 37 | # NOTE: Initially, there are no options set and the source is unknown. 38 | # 39 | array set options {}; set source "" 40 | 41 | # 42 | # NOTE: Calculate the ending list index. This is used in the argument 43 | # processing loop to serve as the loop invariant and to simplify 44 | # the end-of-options checking. This value may be zero. However, 45 | # it cannot be less than zero. 46 | # 47 | set endIndex [expr {[llength $args] - 1}] 48 | 49 | # 50 | # NOTE: Process every argument. The first non-option argument will be 51 | # treated as the "source" argument. It must be the last argument. 52 | # 53 | for {set index 0} {$index <= $endIndex} {incr index} { 54 | # 55 | # NOTE: Grab the current argument, which may be an option. 56 | # 57 | set arg [lindex $args $index] 58 | 59 | # 60 | # NOTE: If this is not the last argument and it starts with a dash, it 61 | # must be an option. 62 | # 63 | if {$index < $endIndex && [string index $arg 0] eq "-"} then { 64 | # 65 | # NOTE: All the options to this sub-command require a value; advance 66 | # to it. 67 | # 68 | incr index 69 | 70 | # 71 | # NOTE: If there are no more arguments left, this is a syntax error. 72 | # 73 | if {$index >= $endIndex} then { 74 | error $compileSyntax 75 | } 76 | 77 | # 78 | # NOTE: If this is the formal end-of-options indicator, do nothing; 79 | # otherwise, record the option value in the options array. 80 | # 81 | if {$arg ne "--"} then { 82 | set options($arg) [lindex $args $index] 83 | } 84 | } elseif {$index == $endIndex} then { 85 | # 86 | # NOTE: This is the last argument, which is the Sass source file 87 | # or string. 88 | # 89 | set source $arg 90 | } else { 91 | # 92 | # NOTE: If this is not an option and not the last argument, this 93 | # is a syntax error. 94 | # 95 | error $compileSyntax 96 | } 97 | } 98 | 99 | # 100 | # NOTE: Check if the type of input is "file". If not, do nothing. 101 | # 102 | if {[info exists options(-type)] && $options(-type) eq "file"} then { 103 | # 104 | # NOTE: Is the "-options" option (not a typo) present? 105 | # 106 | if {[info exists options(-options)]} then { 107 | # 108 | # NOTE: Yes, so grab the value for it. 109 | # 110 | set dictionary $options(-options) 111 | 112 | # 113 | # NOTE: Does the "-options" option value contain the "input_path" 114 | # key? If so, do nothing; otherwise, add it with the value 115 | # of the source file name. 116 | # 117 | if {![dict exists $dictionary input_path]} then { 118 | dict set dictionary input_path $source 119 | } 120 | } else { 121 | # 122 | # NOTE: No, so create an "-options" option value now with just the 123 | # value of the source file name. 124 | # 125 | set dictionary [dict create input_path $source] 126 | } 127 | 128 | # 129 | # NOTE: Modify the "-options" option value to the modified (or brand 130 | # new) dictionary value. 131 | # 132 | set options(-options) $dictionary 133 | } 134 | 135 | # 136 | # NOTE: Start building the final [sass compile] command to be evaluated, 137 | # in the context of the caller. 138 | # 139 | set command [list sass compile] 140 | 141 | # 142 | # NOTE: If there are any options, add them now. 143 | # 144 | if {[array size options] > 0} then { 145 | eval lappend command [array get options] 146 | lappend command -- 147 | } 148 | 149 | # 150 | # NOTE: If we get to this point, there must be a valid source, add it. 151 | # 152 | lappend command $source 153 | 154 | # 155 | # NOTE: Execute the command, in the context of the caller, returning its 156 | # result as our own. 157 | # 158 | uplevel 1 $command 159 | } 160 | 161 | # 162 | # NOTE: This procedure is used by the package index file. It is basically a 163 | # trampoline, designed to permit this script file to be evaluated prior 164 | # to loading the actual library binary. 165 | # 166 | proc load { directory fileName packageName } { 167 | uplevel 1 [list load [file join $directory $fileName] $packageName] 168 | } 169 | 170 | # 171 | # NOTE: Export the [compileWithSass] procedure. 172 | # 173 | namespace export compileWithSass 174 | } 175 | -------------------------------------------------------------------------------- /doc/man.macros: -------------------------------------------------------------------------------- 1 | .\" The -*- nroff -*- definitions below are for supplemental macros used 2 | .\" in Tcl/Tk manual entries. 3 | .\" 4 | .\" .AP type name in/out ?indent? 5 | .\" Start paragraph describing an argument to a library procedure. 6 | .\" type is type of argument (int, etc.), in/out is either "in", "out", 7 | .\" or "in/out" to describe whether procedure reads or modifies arg, 8 | .\" and indent is equivalent to second arg of .IP (shouldn't ever be 9 | .\" needed; use .AS below instead) 10 | .\" 11 | .\" .AS ?type? ?name? 12 | .\" Give maximum sizes of arguments for setting tab stops. Type and 13 | .\" name are examples of largest possible arguments that will be passed 14 | .\" to .AP later. If args are omitted, default tab stops are used. 15 | .\" 16 | .\" .BS 17 | .\" Start box enclosure. From here until next .BE, everything will be 18 | .\" enclosed in one large box. 19 | .\" 20 | .\" .BE 21 | .\" End of box enclosure. 22 | .\" 23 | .\" .CS 24 | .\" Begin code excerpt. 25 | .\" 26 | .\" .CE 27 | .\" End code excerpt. 28 | .\" 29 | .\" .VS ?version? ?br? 30 | .\" Begin vertical sidebar, for use in marking newly-changed parts 31 | .\" of man pages. The first argument is ignored and used for recording 32 | .\" the version when the .VS was added, so that the sidebars can be 33 | .\" found and removed when they reach a certain age. If another argument 34 | .\" is present, then a line break is forced before starting the sidebar. 35 | .\" 36 | .\" .VE 37 | .\" End of vertical sidebar. 38 | .\" 39 | .\" .DS 40 | .\" Begin an indented unfilled display. 41 | .\" 42 | .\" .DE 43 | .\" End of indented unfilled display. 44 | .\" 45 | .\" .SO ?manpage? 46 | .\" Start of list of standard options for a Tk widget. The manpage 47 | .\" argument defines where to look up the standard options; if 48 | .\" omitted, defaults to "options". The options follow on successive 49 | .\" lines, in three columns separated by tabs. 50 | .\" 51 | .\" .SE 52 | .\" End of list of standard options for a Tk widget. 53 | .\" 54 | .\" .OP cmdName dbName dbClass 55 | .\" Start of description of a specific option. cmdName gives the 56 | .\" option's name as specified in the class command, dbName gives 57 | .\" the option's name in the option database, and dbClass gives 58 | .\" the option's class in the option database. 59 | .\" 60 | .\" .UL arg1 arg2 61 | .\" Print arg1 underlined, then print arg2 normally. 62 | .\" 63 | .\" .QW arg1 ?arg2? 64 | .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). 65 | .\" 66 | .\" .PQ arg1 ?arg2? 67 | .\" Print an open parenthesis, arg1 in quotes, then arg2 normally 68 | .\" (for trailing punctuation) and then a closing parenthesis. 69 | .\" 70 | .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. 71 | .if t .wh -1.3i ^B 72 | .nr ^l \n(.l 73 | .ad b 74 | .\" # Start an argument description 75 | .de AP 76 | .ie !"\\$4"" .TP \\$4 77 | .el \{\ 78 | . ie !"\\$2"" .TP \\n()Cu 79 | . el .TP 15 80 | .\} 81 | .ta \\n()Au \\n()Bu 82 | .ie !"\\$3"" \{\ 83 | \&\\$1 \\fI\\$2\\fP (\\$3) 84 | .\".b 85 | .\} 86 | .el \{\ 87 | .br 88 | .ie !"\\$2"" \{\ 89 | \&\\$1 \\fI\\$2\\fP 90 | .\} 91 | .el \{\ 92 | \&\\fI\\$1\\fP 93 | .\} 94 | .\} 95 | .. 96 | .\" # define tabbing values for .AP 97 | .de AS 98 | .nr )A 10n 99 | .if !"\\$1"" .nr )A \\w'\\$1'u+3n 100 | .nr )B \\n()Au+15n 101 | .\" 102 | .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n 103 | .nr )C \\n()Bu+\\w'(in/out)'u+2n 104 | .. 105 | .AS Tcl_Interp Tcl_CreateInterp in/out 106 | .\" # BS - start boxed text 107 | .\" # ^y = starting y location 108 | .\" # ^b = 1 109 | .de BS 110 | .br 111 | .mk ^y 112 | .nr ^b 1u 113 | .if n .nf 114 | .if n .ti 0 115 | .if n \l'\\n(.lu\(ul' 116 | .if n .fi 117 | .. 118 | .\" # BE - end boxed text (draw box now) 119 | .de BE 120 | .nf 121 | .ti 0 122 | .mk ^t 123 | .ie n \l'\\n(^lu\(ul' 124 | .el \{\ 125 | .\" Draw four-sided box normally, but don't draw top of 126 | .\" box if the box started on an earlier page. 127 | .ie !\\n(^b-1 \{\ 128 | \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' 129 | .\} 130 | .el \}\ 131 | \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' 132 | .\} 133 | .\} 134 | .fi 135 | .br 136 | .nr ^b 0 137 | .. 138 | .\" # VS - start vertical sidebar 139 | .\" # ^Y = starting y location 140 | .\" # ^v = 1 (for troff; for nroff this doesn't matter) 141 | .de VS 142 | .if !"\\$2"" .br 143 | .mk ^Y 144 | .ie n 'mc \s12\(br\s0 145 | .el .nr ^v 1u 146 | .. 147 | .\" # VE - end of vertical sidebar 148 | .de VE 149 | .ie n 'mc 150 | .el \{\ 151 | .ev 2 152 | .nf 153 | .ti 0 154 | .mk ^t 155 | \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' 156 | .sp -1 157 | .fi 158 | .ev 159 | .\} 160 | .nr ^v 0 161 | .. 162 | .\" # Special macro to handle page bottom: finish off current 163 | .\" # box/sidebar if in box/sidebar mode, then invoked standard 164 | .\" # page bottom macro. 165 | .de ^B 166 | .ev 2 167 | 'ti 0 168 | 'nf 169 | .mk ^t 170 | .if \\n(^b \{\ 171 | .\" Draw three-sided box if this is the box's first page, 172 | .\" draw two sides but no top otherwise. 173 | .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c 174 | .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c 175 | .\} 176 | .if \\n(^v \{\ 177 | .nr ^x \\n(^tu+1v-\\n(^Yu 178 | \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c 179 | .\} 180 | .bp 181 | 'fi 182 | .ev 183 | .if \\n(^b \{\ 184 | .mk ^y 185 | .nr ^b 2 186 | .\} 187 | .if \\n(^v \{\ 188 | .mk ^Y 189 | .\} 190 | .. 191 | .\" # DS - begin display 192 | .de DS 193 | .RS 194 | .nf 195 | .sp 196 | .. 197 | .\" # DE - end display 198 | .de DE 199 | .fi 200 | .RE 201 | .sp 202 | .. 203 | .\" # SO - start of list of standard options 204 | .de SO 205 | 'ie '\\$1'' .ds So \\fBoptions\\fR 206 | 'el .ds So \\fB\\$1\\fR 207 | .SH "STANDARD OPTIONS" 208 | .LP 209 | .nf 210 | .ta 5.5c 11c 211 | .ft B 212 | .. 213 | .\" # SE - end of list of standard options 214 | .de SE 215 | .fi 216 | .ft R 217 | .LP 218 | See the \\*(So manual entry for details on the standard options. 219 | .. 220 | .\" # OP - start of full description for a single option 221 | .de OP 222 | .LP 223 | .nf 224 | .ta 4c 225 | Command-Line Name: \\fB\\$1\\fR 226 | Database Name: \\fB\\$2\\fR 227 | Database Class: \\fB\\$3\\fR 228 | .fi 229 | .IP 230 | .. 231 | .\" # CS - begin code excerpt 232 | .de CS 233 | .RS 234 | .nf 235 | .ta .25i .5i .75i 1i 236 | .. 237 | .\" # CE - end code excerpt 238 | .de CE 239 | .fi 240 | .RE 241 | .. 242 | .\" # UL - underline word 243 | .de UL 244 | \\$1\l'|0\(ul'\\$2 245 | .. 246 | .\" # QW - apply quotation marks to word 247 | .de QW 248 | .ie '\\*(lq'"' ``\\$1''\\$2 249 | .\"" fix emacs highlighting 250 | .el \\*(lq\\$1\\*(rq\\$2 251 | .. 252 | .\" # PQ - apply parens and quotation marks to word 253 | .de PQ 254 | .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 255 | .\"" fix emacs highlighting 256 | .el (\\*(lq\\$1\\*(rq\\$2)\\$3 257 | .. 258 | .\" # QR - quoted range 259 | .de QR 260 | .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 261 | .\"" fix emacs highlighting 262 | .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 263 | .. 264 | .\" # MT - "empty" string 265 | .de MT 266 | .QW "" 267 | .. 268 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash -norc 2 | dnl This file is an input file used by the GNU "autoconf" program to 3 | dnl generate the file "configure", which is run during Tcl installation 4 | dnl to configure the system for the local environment. 5 | 6 | #----------------------------------------------------------------------- 7 | # Set your package name and version numbers here. 8 | # 9 | # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION 10 | # set as provided. These will also be added as -D defs in your Makefile 11 | # so you can encode the package version directly into the source files. 12 | # This will also define a special symbol for Windows (BUILD_ 13 | # so that we create the export library with the dll. 14 | #----------------------------------------------------------------------- 15 | 16 | AC_INIT([sass], [3.4.5]) 17 | PACKAGE_LIB_PREFIX=tcl 18 | 19 | #----- 20 | # Version with patch stripped 21 | #----- 22 | 23 | AC_SUBST(PKG_MAJ_MIN,`expr $PACKAGE_VERSION : '\(.*\)\..*'`) 24 | 25 | #-------------------------------------------------------------------- 26 | # Call TEA_INIT as the first TEA_ macro to set up initial vars. 27 | # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" 28 | # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. 29 | #-------------------------------------------------------------------- 30 | 31 | TEA_INIT([3.9]) 32 | 33 | AC_CONFIG_AUX_DIR(tclconfig) 34 | 35 | #-------------------------------------------------------------------- 36 | # Load the tclConfig.sh file 37 | #-------------------------------------------------------------------- 38 | 39 | TEA_PATH_TCLCONFIG 40 | TEA_LOAD_TCLCONFIG 41 | 42 | #-------------------------------------------------------------------- 43 | # Load the tkConfig.sh file if necessary (Tk extension) 44 | #-------------------------------------------------------------------- 45 | 46 | #TEA_PATH_TKCONFIG 47 | #TEA_LOAD_TKCONFIG 48 | 49 | #----------------------------------------------------------------------- 50 | # Handle the --prefix=... option by defaulting to what Tcl gave. 51 | # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. 52 | #----------------------------------------------------------------------- 53 | 54 | TEA_PREFIX 55 | 56 | #----------------------------------------------------------------------- 57 | # Standard compiler checks. 58 | # This sets up CC by using the CC env var, or looks for gcc otherwise. 59 | # This also calls AC_PROG_CC and a few others to create the basic setup 60 | # necessary to compile executables. 61 | #----------------------------------------------------------------------- 62 | 63 | TEA_SETUP_COMPILER 64 | 65 | #----------------------------------------------------------------------- 66 | # Specify the C source files to compile in TEA_ADD_SOURCES, 67 | # public headers that need to be installed in TEA_ADD_HEADERS, 68 | # stub library C source files to compile in TEA_ADD_STUB_SOURCES, 69 | # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. 70 | # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS 71 | # and PKG_TCL_SOURCES. 72 | #----------------------------------------------------------------------- 73 | 74 | TEA_ADD_SOURCES([tclsass.c]) 75 | TEA_ADD_HEADERS([generic/tclsass.h]) 76 | TEA_ADD_INCLUDES([]) 77 | TEA_ADD_LIBS([]) 78 | TEA_ADD_CFLAGS([]) 79 | TEA_ADD_STUB_SOURCES([]) 80 | TEA_ADD_TCL_SOURCES([helper.tcl]) 81 | 82 | AC_ARG_VAR([LIBSASS],[Install location of libsass]) 83 | #AC_CHECK_HEADERS([sass/context.h]) 84 | #AC_CHECK_LIB([sass],[libsass_version],, [AC_MSG_ERROR([unable to find libsass library])]) 85 | 86 | #-------------------------------------------------------------------- 87 | # 88 | # You can add more files to clean if your extension creates any extra 89 | # files by extending CLEANFILES. 90 | # Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure 91 | # and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. 92 | # 93 | # A few miscellaneous platform-specific items: 94 | # TEA_ADD_* any platform specific compiler/build info here. 95 | #-------------------------------------------------------------------- 96 | 97 | #CLEANFILES="$CLEANFILES pkgIndex.tcl" 98 | if test "${TEA_PLATFORM}" = "windows" ; then 99 | # Ensure no empty if clauses 100 | : 101 | else 102 | # Ensure no empty else clauses 103 | : 104 | fi 105 | 106 | #-------------------------------------------------------------------- 107 | # Choose which headers you need. Extension authors should try very 108 | # hard to only rely on the Tcl public header files. Internal headers 109 | # contain private data structures and are subject to change without 110 | # notice. 111 | # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG 112 | #-------------------------------------------------------------------- 113 | 114 | TEA_PUBLIC_TCL_HEADERS 115 | #TEA_PRIVATE_TCL_HEADERS 116 | 117 | #TEA_PUBLIC_TK_HEADERS 118 | #TEA_PRIVATE_TK_HEADERS 119 | #TEA_PATH_X 120 | 121 | #-------------------------------------------------------------------- 122 | # Check whether --enable-threads or --disable-threads was given. 123 | # This auto-enables if Tcl was compiled threaded. 124 | #-------------------------------------------------------------------- 125 | 126 | TEA_ENABLE_THREADS 127 | 128 | #-------------------------------------------------------------------- 129 | # The statement below defines a collection of symbols related to 130 | # building as a shared library instead of a static library. 131 | #-------------------------------------------------------------------- 132 | 133 | TEA_ENABLE_SHARED 134 | 135 | #-------------------------------------------------------------------- 136 | # This macro figures out what flags to use with the compiler/linker 137 | # when building shared/static debug/optimized objects. This information 138 | # can be taken from the tclConfig.sh file, but this figures it all out. 139 | #-------------------------------------------------------------------- 140 | 141 | TEA_CONFIG_CFLAGS 142 | 143 | #-------------------------------------------------------------------- 144 | # Set the default compiler switches based on the --enable-symbols option. 145 | #-------------------------------------------------------------------- 146 | 147 | TEA_ENABLE_SYMBOLS 148 | 149 | #-------------------------------------------------------------------- 150 | # Everyone should be linking against the Tcl stub library. If you 151 | # can't for some reason, remove this definition. If you aren't using 152 | # stubs, you also need to modify the SHLIB_LD_LIBS setting below to 153 | # link against the non-stubbed Tcl library. Add Tk too if necessary. 154 | #-------------------------------------------------------------------- 155 | 156 | AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) 157 | #AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) 158 | 159 | #-------------------------------------------------------------------- 160 | # This macro generates a line to use when building a library. It 161 | # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, 162 | # and TEA_LOAD_TCLCONFIG macros above. 163 | #-------------------------------------------------------------------- 164 | 165 | TEA_MAKE_LIB 166 | 167 | #-------------------------------------------------------------------- 168 | # Determine the name of the tclsh and/or wish executables in the 169 | # Tcl and Tk build directories or the location they were installed 170 | # into. These paths are used to support running test cases only, 171 | # the Makefile should not be making use of these paths to generate 172 | # a pkgIndex.tcl file or anything else at extension build time. 173 | #-------------------------------------------------------------------- 174 | 175 | TEA_PROG_TCLSH 176 | #TEA_PROG_WISH 177 | 178 | #-------------------------------------------------------------------- 179 | # Finally, substitute all of the various values into the Makefile. 180 | # You may alternatively have a special pkgIndex.tcl.in or other files 181 | # which require substituting th AC variables in. Include these here. 182 | #-------------------------------------------------------------------- 183 | 184 | AC_OUTPUT([Makefile pkgIndex.tcl]) 185 | -------------------------------------------------------------------------------- /tclconfig/install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2011-04-20.01; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -S $stripprog installed files. 124 | -t DIRECTORY install into DIRECTORY. 125 | -T report an error if DSTFILE is a directory. 126 | 127 | Environment variables override the default commands: 128 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 129 | RMPROG STRIPPROG 130 | " 131 | 132 | while test $# -ne 0; do 133 | case $1 in 134 | -c) ;; 135 | 136 | -C) copy_on_change=true;; 137 | 138 | -d) dir_arg=true;; 139 | 140 | -g) chgrpcmd="$chgrpprog $2" 141 | shift;; 142 | 143 | --help) echo "$usage"; exit $?;; 144 | 145 | -m) mode=$2 146 | case $mode in 147 | *' '* | *' '* | *' 148 | '* | *'*'* | *'?'* | *'['*) 149 | echo "$0: invalid mode: $mode" >&2 150 | exit 1;; 151 | esac 152 | shift;; 153 | 154 | -o) chowncmd="$chownprog $2" 155 | shift;; 156 | 157 | -s) stripcmd=$stripprog;; 158 | 159 | -S) stripcmd="$stripprog $2" 160 | shift;; 161 | 162 | -t) dst_arg=$2 163 | shift;; 164 | 165 | -T) no_target_directory=true;; 166 | 167 | --version) echo "$0 $scriptversion"; exit $?;; 168 | 169 | --) shift 170 | break;; 171 | 172 | -*) echo "$0: invalid option: $1" >&2 173 | exit 1;; 174 | 175 | *) break;; 176 | esac 177 | shift 178 | done 179 | 180 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 181 | # When -d is used, all remaining arguments are directories to create. 182 | # When -t is used, the destination is already specified. 183 | # Otherwise, the last argument is the destination. Remove it from $@. 184 | for arg 185 | do 186 | if test -n "$dst_arg"; then 187 | # $@ is not empty: it contains at least $arg. 188 | set fnord "$@" "$dst_arg" 189 | shift # fnord 190 | fi 191 | shift # arg 192 | dst_arg=$arg 193 | done 194 | fi 195 | 196 | if test $# -eq 0; then 197 | if test -z "$dir_arg"; then 198 | echo "$0: no input file specified." >&2 199 | exit 1 200 | fi 201 | # It's OK to call `install-sh -d' without argument. 202 | # This can happen when creating conditional directories. 203 | exit 0 204 | fi 205 | 206 | if test -z "$dir_arg"; then 207 | do_exit='(exit $ret); exit $ret' 208 | trap "ret=129; $do_exit" 1 209 | trap "ret=130; $do_exit" 2 210 | trap "ret=141; $do_exit" 13 211 | trap "ret=143; $do_exit" 15 212 | 213 | # Set umask so as not to create temps with too-generous modes. 214 | # However, 'strip' requires both read and write access to temps. 215 | case $mode in 216 | # Optimize common cases. 217 | *644) cp_umask=133;; 218 | *755) cp_umask=22;; 219 | 220 | *[0-7]) 221 | if test -z "$stripcmd"; then 222 | u_plus_rw= 223 | else 224 | u_plus_rw='% 200' 225 | fi 226 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 227 | *) 228 | if test -z "$stripcmd"; then 229 | u_plus_rw= 230 | else 231 | u_plus_rw=,u+rw 232 | fi 233 | cp_umask=$mode$u_plus_rw;; 234 | esac 235 | fi 236 | 237 | for src 238 | do 239 | # Protect names starting with `-'. 240 | case $src in 241 | -*) src=./$src;; 242 | esac 243 | 244 | if test -n "$dir_arg"; then 245 | dst=$src 246 | dstdir=$dst 247 | test -d "$dstdir" 248 | dstdir_status=$? 249 | else 250 | 251 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 252 | # might cause directories to be created, which would be especially bad 253 | # if $src (and thus $dsttmp) contains '*'. 254 | if test ! -f "$src" && test ! -d "$src"; then 255 | echo "$0: $src does not exist." >&2 256 | exit 1 257 | fi 258 | 259 | if test -z "$dst_arg"; then 260 | echo "$0: no destination specified." >&2 261 | exit 1 262 | fi 263 | 264 | dst=$dst_arg 265 | # Protect names starting with `-'. 266 | case $dst in 267 | -*) dst=./$dst;; 268 | esac 269 | 270 | # If destination is a directory, append the input filename; won't work 271 | # if double slashes aren't ignored. 272 | if test -d "$dst"; then 273 | if test -n "$no_target_directory"; then 274 | echo "$0: $dst_arg: Is a directory" >&2 275 | exit 1 276 | fi 277 | dstdir=$dst 278 | dst=$dstdir/`basename "$src"` 279 | dstdir_status=0 280 | else 281 | # Prefer dirname, but fall back on a substitute if dirname fails. 282 | dstdir=` 283 | (dirname "$dst") 2>/dev/null || 284 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 285 | X"$dst" : 'X\(//\)[^/]' \| \ 286 | X"$dst" : 'X\(//\)$' \| \ 287 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 288 | echo X"$dst" | 289 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 290 | s//\1/ 291 | q 292 | } 293 | /^X\(\/\/\)[^/].*/{ 294 | s//\1/ 295 | q 296 | } 297 | /^X\(\/\/\)$/{ 298 | s//\1/ 299 | q 300 | } 301 | /^X\(\/\).*/{ 302 | s//\1/ 303 | q 304 | } 305 | s/.*/./; q' 306 | ` 307 | 308 | test -d "$dstdir" 309 | dstdir_status=$? 310 | fi 311 | fi 312 | 313 | obsolete_mkdir_used=false 314 | 315 | if test $dstdir_status != 0; then 316 | case $posix_mkdir in 317 | '') 318 | # Create intermediate dirs using mode 755 as modified by the umask. 319 | # This is like FreeBSD 'install' as of 1997-10-28. 320 | umask=`umask` 321 | case $stripcmd.$umask in 322 | # Optimize common cases. 323 | *[2367][2367]) mkdir_umask=$umask;; 324 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 325 | 326 | *[0-7]) 327 | mkdir_umask=`expr $umask + 22 \ 328 | - $umask % 100 % 40 + $umask % 20 \ 329 | - $umask % 10 % 4 + $umask % 2 330 | `;; 331 | *) mkdir_umask=$umask,go-w;; 332 | esac 333 | 334 | # With -d, create the new directory with the user-specified mode. 335 | # Otherwise, rely on $mkdir_umask. 336 | if test -n "$dir_arg"; then 337 | mkdir_mode=-m$mode 338 | else 339 | mkdir_mode= 340 | fi 341 | 342 | posix_mkdir=false 343 | case $umask in 344 | *[123567][0-7][0-7]) 345 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 346 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 347 | ;; 348 | *) 349 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 350 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 351 | 352 | if (umask $mkdir_umask && 353 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 354 | then 355 | if test -z "$dir_arg" || { 356 | # Check for POSIX incompatibilities with -m. 357 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 358 | # other-writeable bit of parent directory when it shouldn't. 359 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 360 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 361 | case $ls_ld_tmpdir in 362 | d????-?r-*) different_mode=700;; 363 | d????-?--*) different_mode=755;; 364 | *) false;; 365 | esac && 366 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 367 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 368 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 369 | } 370 | } 371 | then posix_mkdir=: 372 | fi 373 | rmdir "$tmpdir/d" "$tmpdir" 374 | else 375 | # Remove any dirs left behind by ancient mkdir implementations. 376 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 377 | fi 378 | trap '' 0;; 379 | esac;; 380 | esac 381 | 382 | if 383 | $posix_mkdir && ( 384 | umask $mkdir_umask && 385 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 386 | ) 387 | then : 388 | else 389 | 390 | # The umask is ridiculous, or mkdir does not conform to POSIX, 391 | # or it failed possibly due to a race condition. Create the 392 | # directory the slow way, step by step, checking for races as we go. 393 | 394 | case $dstdir in 395 | /*) prefix='/';; 396 | -*) prefix='./';; 397 | *) prefix='';; 398 | esac 399 | 400 | eval "$initialize_posix_glob" 401 | 402 | oIFS=$IFS 403 | IFS=/ 404 | $posix_glob set -f 405 | set fnord $dstdir 406 | shift 407 | $posix_glob set +f 408 | IFS=$oIFS 409 | 410 | prefixes= 411 | 412 | for d 413 | do 414 | test -z "$d" && continue 415 | 416 | prefix=$prefix$d 417 | if test -d "$prefix"; then 418 | prefixes= 419 | else 420 | if $posix_mkdir; then 421 | (umask=$mkdir_umask && 422 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 423 | # Don't fail if two instances are running concurrently. 424 | test -d "$prefix" || exit 1 425 | else 426 | case $prefix in 427 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 428 | *) qprefix=$prefix;; 429 | esac 430 | prefixes="$prefixes '$qprefix'" 431 | fi 432 | fi 433 | prefix=$prefix/ 434 | done 435 | 436 | if test -n "$prefixes"; then 437 | # Don't fail if two instances are running concurrently. 438 | (umask $mkdir_umask && 439 | eval "\$doit_exec \$mkdirprog $prefixes") || 440 | test -d "$dstdir" || exit 1 441 | obsolete_mkdir_used=true 442 | fi 443 | fi 444 | fi 445 | 446 | if test -n "$dir_arg"; then 447 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 448 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 449 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 450 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 451 | else 452 | 453 | # Make a couple of temp file names in the proper directory. 454 | dsttmp=$dstdir/_inst.$$_ 455 | rmtmp=$dstdir/_rm.$$_ 456 | 457 | # Trap to clean up those temp files at exit. 458 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 459 | 460 | # Copy the file name to the temp name. 461 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 462 | 463 | # and set any options; do chmod last to preserve setuid bits. 464 | # 465 | # If any of these fail, we abort the whole thing. If we want to 466 | # ignore errors from any of these, just make sure not to ignore 467 | # errors from the above "$doit $cpprog $src $dsttmp" command. 468 | # 469 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 470 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 471 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 472 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 473 | 474 | # If -C, don't bother to copy if it wouldn't change the file. 475 | if $copy_on_change && 476 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 477 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 478 | 479 | eval "$initialize_posix_glob" && 480 | $posix_glob set -f && 481 | set X $old && old=:$2:$4:$5:$6 && 482 | set X $new && new=:$2:$4:$5:$6 && 483 | $posix_glob set +f && 484 | 485 | test "$old" = "$new" && 486 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 487 | then 488 | rm -f "$dsttmp" 489 | else 490 | # Rename the file to the real destination. 491 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 492 | 493 | # The rename failed, perhaps because mv can't rename something else 494 | # to itself, or perhaps because mv is so ancient that it does not 495 | # support -f. 496 | { 497 | # Now remove or move aside any old file at destination location. 498 | # We try this two ways since rm can't unlink itself on some 499 | # systems and the destination file might be busy for other 500 | # reasons. In this case, the final cleanup might fail but the new 501 | # file should still install successfully. 502 | { 503 | test ! -f "$dst" || 504 | $doit $rmcmd -f "$dst" 2>/dev/null || 505 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 506 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 507 | } || 508 | { echo "$0: cannot unlink or rename $dst" >&2 509 | (exit 1); exit 1 510 | } 511 | } && 512 | 513 | # Now rename the file to the real destination. 514 | $doit $mvcmd "$dsttmp" "$dst" 515 | } 516 | fi || exit 1 517 | 518 | trap '' 0 519 | fi 520 | done 521 | 522 | # Local variables: 523 | # eval: (add-hook 'write-file-hooks 'time-stamp) 524 | # time-stamp-start: "scriptversion=" 525 | # time-stamp-format: "%:y-%02m-%02d.%02H" 526 | # time-stamp-time-zone: "UTC" 527 | # time-stamp-end: "; # UTC" 528 | # End: 529 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in -- 2 | # 3 | # This file is a Makefile for libsass TEA Extension. If it has the name 4 | # "Makefile.in" then it is a template for a Makefile; to generate the 5 | # actual Makefile, run "./configure", which is a configuration script 6 | # generated by the "autoconf" program (constructs like "@foo@" will get 7 | # replaced in the actual Makefile. 8 | # 9 | # Copyright (c) 1999 Scriptics Corporation. 10 | # Copyright (c) 2002-2005 ActiveState Corporation. 11 | # 12 | # See the file "license.terms" for information on usage and redistribution 13 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 14 | 15 | #======================================================================== 16 | # Nothing of the variables below this line should need to be changed. 17 | # Please check the TARGETS section below to make sure the make targets 18 | # are correct. 19 | #======================================================================== 20 | 21 | #======================================================================== 22 | # The names of the source files is defined in the configure script. 23 | # The object files are used for linking into the final library. 24 | # This will be used when a dist target is added to the Makefile. 25 | # It is not important to specify the directory, as long as it is the 26 | # $(srcdir) or in the generic, win or unix subdirectory. 27 | #======================================================================== 28 | 29 | PKG_SOURCES = @PKG_SOURCES@ 30 | PKG_OBJECTS = @PKG_OBJECTS@ 31 | 32 | PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ 33 | PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ 34 | 35 | #======================================================================== 36 | # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with 37 | # this package that need to be installed, if any. 38 | #======================================================================== 39 | 40 | PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ 41 | 42 | #======================================================================== 43 | # This is a list of public header files to be installed, if any. 44 | #======================================================================== 45 | 46 | PKG_HEADERS = @PKG_HEADERS@ 47 | 48 | #======================================================================== 49 | # "PKG_LIB_FILE" refers to the library (dynamic or static as per 50 | # configuration options) composed of the named objects. 51 | #======================================================================== 52 | 53 | PKG_LIB_FILE = @PKG_LIB_FILE@ 54 | PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ 55 | 56 | lib_BINARIES = $(PKG_LIB_FILE) 57 | BINARIES = $(lib_BINARIES) 58 | 59 | SHELL = @SHELL@ 60 | 61 | srcdir = @srcdir@ 62 | prefix = @prefix@ 63 | exec_prefix = @exec_prefix@ 64 | 65 | bindir = @bindir@ 66 | libdir = @libdir@ 67 | includedir = @includedir@ 68 | datarootdir = @datarootdir@ 69 | datadir = @datadir@ 70 | mandir = @mandir@ 71 | 72 | DESTDIR = 73 | 74 | PKG_DIR = $(PACKAGE_NAME)$(PKG_MAJ_MIN) 75 | pkgdatadir = $(datadir)/$(PKG_DIR) 76 | pkglibdir = $(libdir)/$(PKG_DIR) 77 | pkgincludedir = $(includedir)/$(PKG_DIR) 78 | 79 | top_builddir = . 80 | 81 | INSTALL_OPTIONS = 82 | INSTALL = @INSTALL@ ${INSTALL_OPTIONS} 83 | INSTALL_DATA_DIR = @INSTALL_DATA_DIR@ 84 | INSTALL_DATA = @INSTALL_DATA@ 85 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 86 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 87 | INSTALL_LIBRARY = @INSTALL_LIBRARY@ 88 | 89 | PACKAGE_NAME = @PACKAGE_NAME@ 90 | PACKAGE_VERSION = @PACKAGE_VERSION@ 91 | PKG_MAJ_MIN = @PKG_MAJ_MIN@ 92 | CC = @CC@ 93 | CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ -I@LIBSASS@/include 94 | CFLAGS_WARNING = @CFLAGS_WARNING@ 95 | EXEEXT = @EXEEXT@ 96 | LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ 97 | MAKE_LIB = @MAKE_LIB@ 98 | MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ 99 | MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ 100 | MAKE_STUB_LIB = @MAKE_STUB_LIB@ 101 | OBJEXT = @OBJEXT@ 102 | RANLIB = @RANLIB@ 103 | RANLIB_STUB = @RANLIB_STUB@ 104 | SHLIB_CFLAGS = @SHLIB_CFLAGS@ 105 | SHLIB_LD = @SHLIB_LD@ 106 | SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ -L@LIBSASS@/lib -lsass -Wl,-rpath=@LIBSASS@/lib 107 | STLIB_LD = @STLIB_LD@ 108 | #TCL_DEFS = @TCL_DEFS@ 109 | TCL_BIN_DIR = @TCL_BIN_DIR@ 110 | TCL_SRC_DIR = @TCL_SRC_DIR@ 111 | #TK_BIN_DIR = @TK_BIN_DIR@ 112 | #TK_SRC_DIR = @TK_SRC_DIR@ 113 | 114 | # Not used, but retained for reference of what libs Tcl required 115 | #TCL_LIBS = @TCL_LIBS@ 116 | 117 | #======================================================================== 118 | # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our 119 | # package without installing. The other environment variables allow us 120 | # to test against an uninstalled Tcl. Add special env vars that you 121 | # require for testing here (like TCLX_LIBRARY). 122 | #======================================================================== 123 | 124 | EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) 125 | #EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) 126 | TCLLIBPATH = $(top_builddir) 127 | TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` 128 | PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ 129 | PATH="$(EXTRA_PATH):$(PATH)" \ 130 | TCLLIBPATH="$(TCLLIBPATH)" 131 | 132 | TCLSH_PROG = @TCLSH_PROG@ 133 | TCLSH = $(PKG_ENV) $(TCLSH_ENV) $(TCLSH_PROG) 134 | 135 | #WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` 136 | #WISH_PROG = @WISH_PROG@ 137 | #WISH = $(PKG_ENV) $(TCLSH_ENV) $(WISH_ENV) $(WISH_PROG) 138 | 139 | SHARED_BUILD = @SHARED_BUILD@ 140 | 141 | INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ 142 | #INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ 143 | 144 | PKG_CFLAGS = @PKG_CFLAGS@ 145 | 146 | # TCL_DEFS is not strictly need here, but if you remove it, then you 147 | # must make sure that configure.in checks for the necessary components 148 | # that your library may use. TCL_DEFS can actually be a problem if 149 | # you do not compile with a similar machine setup as the Tcl core was 150 | # compiled with. 151 | #DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) 152 | DEFS = @DEFS@ $(PKG_CFLAGS) 153 | 154 | # Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile 155 | CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl 156 | CLEANFILES = @CLEANFILES@ 157 | 158 | CPPFLAGS = @CPPFLAGS@ 159 | LIBS = @PKG_LIBS@ @LIBS@ 160 | AR = @AR@ 161 | CFLAGS = @CFLAGS@ 162 | COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) 163 | 164 | .SUFFIXES: .c .$(OBJEXT) 165 | 166 | #======================================================================== 167 | # Start of user-definable TARGETS section 168 | #======================================================================== 169 | 170 | #======================================================================== 171 | # TEA TARGETS. Please note that the "libraries:" target refers to platform 172 | # independent files, and the "binaries:" target includes executable programs and 173 | # platform-dependent libraries. Modify these targets so that they install 174 | # the various pieces of your package. The make and install rules 175 | # for the BINARIES that you specified above have already been done. 176 | #======================================================================== 177 | 178 | all: binaries libraries doc 179 | 180 | #======================================================================== 181 | # The binaries target builds executable programs, Windows .dll's, unix 182 | # shared/static libraries, and any other platform-dependent files. 183 | # The list of targets to build for "binaries:" is specified at the top 184 | # of the Makefile, in the "BINARIES" variable. 185 | #======================================================================== 186 | 187 | binaries: $(BINARIES) 188 | 189 | libraries: 190 | 191 | #======================================================================== 192 | # Your doc target should differentiate from doc builds (by the developer) 193 | # and doc installs (see install-doc), which just install the docs on the 194 | # end user machine when building from source. 195 | #======================================================================== 196 | 197 | doc: 198 | @echo "If you have documentation to create, place the commands to" 199 | @echo "build the docs in the 'doc:' target. For example:" 200 | @echo " xml2nroff sample.xml > sample.n" 201 | @echo " xml2html sample.xml > sample.html" 202 | 203 | install: all install-binaries install-libraries install-doc 204 | 205 | install-binaries: binaries install-lib-binaries install-bin-binaries 206 | 207 | #======================================================================== 208 | # This rule installs platform-independent files, such as header files. 209 | # The list=...; for p in $$list handles the empty list case x-platform. 210 | #======================================================================== 211 | 212 | install-libraries: libraries 213 | @$(INSTALL_DATA_DIR) $(DESTDIR)$(includedir) 214 | @echo "Installing header files in $(DESTDIR)$(includedir)" 215 | @list='$(PKG_HEADERS)'; for i in $$list; do \ 216 | echo "Installing $(srcdir)/$$i" ; \ 217 | $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ 218 | done; 219 | 220 | #======================================================================== 221 | # Install documentation. Unix manpages should go in the $(mandir) 222 | # directory. 223 | #======================================================================== 224 | 225 | install-doc: doc 226 | @$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/mann 227 | @echo "Installing documentation in $(DESTDIR)$(mandir)" 228 | @list='$(srcdir)/doc/*.n'; for i in $$list; do \ 229 | echo "Installing $$i"; \ 230 | $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ 231 | done 232 | 233 | test: binaries libraries 234 | $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ 235 | -load "package ifneeded ${PACKAGE_NAME} ${PACKAGE_VERSION} \ 236 | [list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" 237 | 238 | shell: binaries libraries 239 | @$(TCLSH) $(SCRIPT) 240 | 241 | gdb: 242 | $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) 243 | 244 | VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \ 245 | --leak-check=yes --show-reachable=yes -v 246 | 247 | valgrind: binaries libraries 248 | $(TCLSH_ENV) valgrind $(VALGRINDARGS) $(TCLSH_PROG) \ 249 | `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) 250 | 251 | valgrindshell: binaries libraries 252 | $(TCLSH_ENV) valgrind $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT) 253 | 254 | depend: 255 | 256 | #======================================================================== 257 | # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable 258 | # mentioned above. That will ensure that this target is built when you 259 | # run "make binaries". 260 | # 261 | # The $(PKG_OBJECTS) objects are created and linked into the final 262 | # library. In most cases these object files will correspond to the 263 | # source files above. 264 | #======================================================================== 265 | 266 | $(PKG_LIB_FILE): $(PKG_OBJECTS) 267 | -rm -f $(PKG_LIB_FILE) 268 | ${MAKE_LIB} 269 | $(RANLIB) $(PKG_LIB_FILE) 270 | 271 | $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) 272 | -rm -f $(PKG_STUB_LIB_FILE) 273 | ${MAKE_STUB_LIB} 274 | $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) 275 | 276 | #======================================================================== 277 | # We need to enumerate the list of .c to .o lines here. 278 | # 279 | # In the following lines, $(srcdir) refers to the toplevel directory 280 | # containing your extension. If your sources are in a subdirectory, 281 | # you will have to modify the paths to reflect this: 282 | # 283 | # sample.$(OBJEXT): $(srcdir)/generic/sample.c 284 | # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ 285 | # 286 | # Setting the VPATH variable to a list of paths will cause the makefile 287 | # to look into these paths when resolving .c to .obj dependencies. 288 | # As necessary, add $(srcdir):$(srcdir)/compat:.... 289 | #======================================================================== 290 | 291 | VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macosx 292 | 293 | .c.@OBJEXT@: 294 | $(COMPILE) -c `@CYGPATH@ $<` -o $@ 295 | 296 | #======================================================================== 297 | # Distribution creation 298 | # You may need to tweak this target to make it work correctly. 299 | #======================================================================== 300 | 301 | #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar 302 | COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) 303 | DIST_ROOT = /tmp/dist 304 | DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) 305 | 306 | dist-clean: 307 | rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* 308 | 309 | dist: dist-clean 310 | $(INSTALL_DATA_DIR) $(DIST_DIR) 311 | cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \ 312 | $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ 313 | $(DIST_DIR)/ 314 | chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 315 | chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in 316 | 317 | for i in $(srcdir)/*.[ch]; do \ 318 | if [ -f $$i ]; then \ 319 | cp -p $$i $(DIST_DIR)/ ; \ 320 | fi; \ 321 | done; 322 | 323 | $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig 324 | cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ 325 | $(DIST_DIR)/tclconfig/ 326 | chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 327 | chmod +x $(DIST_DIR)/tclconfig/install-sh 328 | 329 | list='demos doc generic library mac tests unix win'; \ 330 | for p in $$list; do \ 331 | if test -d $(srcdir)/$$p ; then \ 332 | $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \ 333 | cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ 334 | fi; \ 335 | done 336 | 337 | (cd $(DIST_ROOT); $(COMPRESS);) 338 | 339 | #======================================================================== 340 | # End of user-definable section 341 | #======================================================================== 342 | 343 | #======================================================================== 344 | # Don't modify the file to clean here. Instead, set the "CLEANFILES" 345 | # variable in configure.in 346 | #======================================================================== 347 | 348 | clean: 349 | -test -z "$(BINARIES)" || rm -f $(BINARIES) 350 | -rm -f *.$(OBJEXT) core *.core 351 | -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) 352 | 353 | distclean: clean 354 | -rm -f *.tab.c 355 | -rm -f $(CONFIG_CLEAN_FILES) 356 | -rm -f config.cache config.log config.status 357 | 358 | #======================================================================== 359 | # Install binary object libraries. On Windows this includes both .dll and 360 | # .lib files. Because the .lib files are not explicitly listed anywhere, 361 | # we need to deduce their existence from the .dll file of the same name. 362 | # Library files go into the lib directory. 363 | # In addition, this will generate the pkgIndex.tcl 364 | # file in the install location (assuming it can find a usable tclsh shell) 365 | # 366 | # You should not have to modify this target. 367 | #======================================================================== 368 | 369 | install-lib-binaries: binaries 370 | @$(INSTALL_DATA_DIR) $(DESTDIR)$(pkglibdir) 371 | @list='$(lib_BINARIES)'; for p in $$list; do \ 372 | if test -f $$p; then \ 373 | echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ 374 | $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p; \ 375 | stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ 376 | if test "x$$stub" = "xstub"; then \ 377 | echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ 378 | $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ 379 | else \ 380 | echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ 381 | $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ 382 | fi; \ 383 | ext=`echo $$p|sed -e "s/.*\.//"`; \ 384 | if test "x$$ext" = "xdll"; then \ 385 | lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ 386 | if test -f $$lib; then \ 387 | echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ 388 | $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ 389 | fi; \ 390 | fi; \ 391 | fi; \ 392 | done 393 | @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ 394 | if test -f $(srcdir)/$$p; then \ 395 | destp=`basename $$p`; \ 396 | echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ 397 | $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ 398 | fi; \ 399 | done 400 | @if test "x$(SHARED_BUILD)" = "x1"; then \ 401 | echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ 402 | $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ 403 | fi 404 | 405 | #======================================================================== 406 | # Install binary executables (e.g. .exe files and dependent .dll files) 407 | # This is for files that must go in the bin directory (located next to 408 | # wish and tclsh), like dependent .dll files on Windows. 409 | # 410 | # You should not have to modify this target, except to define bin_BINARIES 411 | # above if necessary. 412 | #======================================================================== 413 | 414 | install-bin-binaries: binaries 415 | @$(INSTALL_DATA_DIR) $(DESTDIR)$(bindir) 416 | @list='$(bin_BINARIES)'; for p in $$list; do \ 417 | if test -f $$p; then \ 418 | echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ 419 | $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ 420 | fi; \ 421 | done 422 | 423 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 424 | cd $(top_builddir) \ 425 | && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status 426 | 427 | uninstall-binaries: 428 | list='$(lib_BINARIES)'; for p in $$list; do \ 429 | rm -f $(DESTDIR)$(pkglibdir)/$$p; \ 430 | done 431 | list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ 432 | p=`basename $$p`; \ 433 | rm -f $(DESTDIR)$(pkglibdir)/$$p; \ 434 | done 435 | list='$(bin_BINARIES)'; for p in $$list; do \ 436 | rm -f $(DESTDIR)$(bindir)/$$p; \ 437 | done 438 | 439 | .PHONY: all binaries clean depend distclean doc install libraries test 440 | 441 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 442 | # Otherwise a system limit (for SysV at least) may be exceeded. 443 | .NOEXPORT: 444 | -------------------------------------------------------------------------------- /tests/sass.test: -------------------------------------------------------------------------------- 1 | # Commands covered: sass 2 | # 3 | # This file contains a collection of tests for one or more of the Tcl 4 | # package commands. Sourcing this file into Tcl runs the tests and 5 | # generates output for errors. No output means no errors were found. 6 | # 7 | # Written by Joe Mistachkin. 8 | # 9 | # See the file "license.terms" for information on usage and redistribution 10 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 | 12 | if {[lsearch [namespace children] ::tcltest] == -1} then { 13 | package require tcltest 14 | namespace import ::tcltest::* 15 | } 16 | 17 | set path [file normalize [file dirname [info script]]] 18 | package require sass 19 | 20 | ############################################################################### 21 | 22 | if {[llength [info commands appendArgs]] == 0} then { 23 | proc appendArgs { args } { 24 | set result ""; eval append result $args 25 | } 26 | } 27 | 28 | ############################################################################### 29 | 30 | if {[llength [info commands getEnvVar]] == 0} then { 31 | proc getEnvVar { name } { 32 | return [expr {[info exists ::env($name)] ? $::env($name) : ""}] 33 | } 34 | } 35 | 36 | ############################################################################### 37 | 38 | if {[llength [info commands getDictValue]] == 0} then { 39 | proc getDictValue { dictionary name {default ""} {wrap ""} } { 40 | if {[llength [info commands dict]] > 0} then { 41 | if {[dict exists $dictionary $name]} then { 42 | return [appendArgs $wrap [dict get $dictionary $name] $wrap] 43 | } 44 | return $default 45 | } else { 46 | foreach {pairName pairValue} $dictionary { 47 | if {$pairName eq $name} then { 48 | return [appendArgs $wrap $pairValue $wrap] 49 | } 50 | } 51 | return $default 52 | } 53 | } 54 | } 55 | 56 | ############################################################################### 57 | 58 | if {[llength [info commands getTempPath]] == 0} then { 59 | proc getTempPath {} { 60 | global tcl_platform 61 | set names [list] 62 | foreach name [list TEMP TMP] { 63 | lappend names [string toupper $name] [string tolower $name] \ 64 | [string totitle $name] 65 | } 66 | foreach name $names { 67 | set value [getEnvVar $name] 68 | if {[string length $value] > 0} then { 69 | return [file normalize $value] 70 | } 71 | } 72 | if {[info exists tcl_platform(platform)]} then { 73 | if {$tcl_platform(platform) ne "windows"} then { 74 | return /tmp; # TODO: Good default on Unix? 75 | } 76 | } 77 | error "no temporary path is available" 78 | } 79 | } 80 | 81 | ############################################################################### 82 | 83 | set scss(1) { 84 | @mixin border-radius($radius) { 85 | -webkit-border-radius: $radius; 86 | -moz-border-radius: $radius; 87 | -ms-border-radius: $radius; 88 | border-radius: $radius; 89 | } 90 | 91 | .box { @include border-radius(10px); } 92 | } 93 | 94 | ############################################################################### 95 | 96 | set scss(2) { 97 | $font-stack: Helvetica, sans-serif; 98 | $primary-color: #333; 99 | 100 | body { 101 | font: 100% $font-stack; 102 | color: $primary-color; 103 | width: 31.123456%; 104 | } 105 | } 106 | 107 | ############################################################################### 108 | 109 | test sass-1.1 {overall command usage} -body { 110 | list [catch {sass} errMsg] $errMsg 111 | } -cleanup { 112 | unset -nocomplain errMsg 113 | } -result {1 {wrong # args: should be "sass option ?arg ...?"}} 114 | 115 | ############################################################################### 116 | 117 | test sass-2.1 {version sub-command usage} -body { 118 | list [catch {sass version foo} errMsg] $errMsg 119 | } -cleanup { 120 | unset -nocomplain errMsg 121 | } -result {1 {wrong # args: should be "sass version"}} 122 | 123 | ############################################################################### 124 | 125 | test sass-2.2 {version sub-command output} -body { 126 | sass version 127 | } -match regexp -result {^libsass\ 128 | \d+\.\d+\.\d+(?:-\d+(?:-g[0-9a-f]+(?:-dirty)?)?|-beta\.\d+(?:-dirty)?)?$} 129 | 130 | ############################################################################### 131 | 132 | test sass-3.1 {compile sub-command usage} -body { 133 | list [catch {sass compile} errMsg] $errMsg 134 | } -cleanup { 135 | unset -nocomplain errMsg 136 | } -result {1 {wrong # args: should be "sass compile ?options? source"}} 137 | 138 | ############################################################################### 139 | 140 | test sass-3.2 {compile sub-command compile error} -body { 141 | set dictionary [sass compile ""] 142 | 143 | list [getDictValue $dictionary errorStatus] \ 144 | [getDictValue $dictionary outputString] \ 145 | [getDictValue $dictionary sourceMapString] \ 146 | [getDictValue $dictionary errorMessage] 147 | } -cleanup { 148 | unset -nocomplain dictionary 149 | } -result {3 {} {} {Internal Error: Data context created with empty source string 150 | }} 151 | 152 | ############################################################################### 153 | 154 | test sass-3.3 {compile sub-command syntax error} -body { 155 | set dictionary [sass compile test] 156 | 157 | list [getDictValue $dictionary errorStatus] \ 158 | [getDictValue $dictionary outputString] \ 159 | [getDictValue $dictionary sourceMapString] \ 160 | [getDictValue $dictionary errorMessage] 161 | } -cleanup { 162 | unset -nocomplain dictionary 163 | } -result {1 {} {} Error:\ Invalid\ CSS\ after\ \"test\":\ expected\ \"\{\",\ was\ \"\"\n\ \ \ \ \ \ \ \ on\ line\ 1\ of\ stdin\n>>\ test\n\ \ \ ^\n} 164 | 165 | ############################################################################### 166 | 167 | test sass-3.4 {compile sub-command output} -body { 168 | set dictionary [sass compile $scss(1)] 169 | 170 | list [getDictValue $dictionary errorStatus] \ 171 | [getDictValue $dictionary outputString] \ 172 | [getDictValue $dictionary sourceMapString] \ 173 | [getDictValue $dictionary errorMessage] 174 | } -cleanup { 175 | unset -nocomplain dictionary 176 | } -result {0 {.box { 177 | -webkit-border-radius: 10px; 178 | -moz-border-radius: 10px; 179 | -ms-border-radius: 10px; 180 | border-radius: 10px; } 181 | } {} {}} 182 | 183 | ############################################################################### 184 | 185 | test sass-3.5 {compile sub-command output w/data} -body { 186 | set dictionary [sass compile -type data $scss(1)] 187 | 188 | list [getDictValue $dictionary errorStatus] \ 189 | [getDictValue $dictionary outputString] \ 190 | [getDictValue $dictionary sourceMapString] \ 191 | [getDictValue $dictionary errorMessage] 192 | } -cleanup { 193 | unset -nocomplain dictionary 194 | } -result {0 {.box { 195 | -webkit-border-radius: 10px; 196 | -moz-border-radius: 10px; 197 | -ms-border-radius: 10px; 198 | border-radius: 10px; } 199 | } {} {}} 200 | 201 | ############################################################################### 202 | 203 | test sass-3.6 {compile sub-command output w/good file} -body { 204 | sass compile -type file -options \ 205 | [list input_path [file join $path good.scss]] \ 206 | [file join $path good.scss] 207 | } -result {errorStatus 0 outputString {body { 208 | font: 100% Helvetica, sans-serif; 209 | color: #333; } 210 | }} 211 | 212 | ############################################################################### 213 | 214 | test sass-3.7 {compile sub-command w/helper procedure} -body { 215 | tclsass::compileWithSass -type file [file join $path good.scss] 216 | } -cleanup { 217 | unset -nocomplain fileName 218 | } -result {errorStatus 0 outputString {body { 219 | font: 100% Helvetica, sans-serif; 220 | color: #333; } 221 | }} 222 | 223 | ############################################################################### 224 | 225 | set fileName [file join $path bad.scss] 226 | 227 | ############################################################################### 228 | 229 | test sass-3.8 {compile sub-command output w/bad file} -body { 230 | sass compile -type file -options \ 231 | [list input_path $fileName] $fileName 232 | } -cleanup { 233 | unset -nocomplain fileName 234 | } -result \ 235 | [subst {errorStatus 1 errorMessage {Error: Invalid CSS after "T": expected 1 selector or at-rule, was "This is not good SC" 236 | on line 1 of tests/bad.scss 237 | >> This is not good SCSS. 238 | ^ 239 | } errorLine 1 errorColumn 1}] 240 | 241 | ############################################################################### 242 | 243 | unset -nocomplain fileName 244 | 245 | ############################################################################### 246 | 247 | test sass-4.1 {malformed options} -body { 248 | list [catch { 249 | sass compile -options [list foo] $scss(2) 250 | } errMsg] $errMsg 251 | } -cleanup { 252 | unset -nocomplain errMsg 253 | } -result {1 {malformed dictionary 254 | }} 255 | 256 | ############################################################################### 257 | 258 | test sass-4.2 {option unknown} -body { 259 | list [catch { 260 | sass compile -options [list foo bar] $scss(2) 261 | } errMsg] $errMsg 262 | } -cleanup { 263 | unset -nocomplain errMsg 264 | } -result {1 {unknown option, must be: precision, output_style,\ 265 | source_comments, source_map_embed, source_map_contents, omit_source_map_url,\ 266 | is_indented_syntax_src, indent, linefeed, input_path, output_path, image_path,\ 267 | include_path, or source_map_file 268 | }} 269 | 270 | ############################################################################### 271 | 272 | test sass-4.3 {option precision (int)} -body { 273 | list [catch { 274 | sass compile -options [list precision 2] $scss(2) 275 | } errMsg] $errMsg [catch { 276 | sass compile -options [list precision x] $scss(2) 277 | } errMsg] $errMsg 278 | } -cleanup { 279 | unset -nocomplain errMsg 280 | } -result {0 {errorStatus 0 outputString {body { 281 | font: 100% Helvetica, sans-serif; 282 | color: #333; 283 | width: 31.123456%; } 284 | }} 1 {expected integer but got "x"}} 285 | 286 | ############################################################################### 287 | 288 | test sass-4.4 {option output_style (enum)} -body { 289 | list [catch { 290 | sass compile -options [list output_style compressed] $scss(2) 291 | } errMsg] $errMsg [catch { 292 | sass compile -options [list output_style x] $scss(2) 293 | } errMsg] $errMsg 294 | } -cleanup { 295 | unset -nocomplain errMsg 296 | } -result {0 {errorStatus 0 outputString {body{font:100%\ 297 | Helvetica,sans-serif;color:#333;width:31.123456%} 298 | }} 1 {unsupported output style,\ 299 | must be: nested, expanded, compact, or compressed 300 | }} 301 | 302 | ############################################################################### 303 | 304 | test sass-4.5 {option source_comments (bool)} -body { 305 | list [catch { 306 | sass compile -options [list source_comments true] $scss(2) 307 | } errMsg] $errMsg [catch { 308 | sass compile -options [list source_comments x] $scss(2) 309 | } errMsg] $errMsg 310 | } -cleanup { 311 | unset -nocomplain errMsg 312 | } -result {0 {errorStatus 0 outputString {/* line 5, stdin */ 313 | body { 314 | font: 100% Helvetica, sans-serif; 315 | color: #333; 316 | width: 31.123456%; } 317 | }} 1 {expected boolean value but got "x"}} 318 | 319 | ############################################################################### 320 | 321 | test sass-4.6 {option source_map_embed (bool)} -body { 322 | list [catch { 323 | sass compile -options [list source_map_embed true] $scss(2) 324 | } errMsg] $errMsg [catch { 325 | sass compile -options [list source_map_embed x] $scss(2) 326 | } errMsg] $errMsg 327 | } -cleanup { 328 | unset -nocomplain errMsg 329 | } -result {0 {errorStatus 0 outputString {body { 330 | font: 100% Helvetica, sans-serif; 331 | color: #333; 332 | width: 31.123456%; } 333 | 334 | /*# sourceMappingURL=data:application/json;base64,ewoJInZlcnNpb24iOiAzLAoJImZpbGUiOiAic3RkaW4uY3NzIiwKCSJzb3VyY2VzIjogWwoJCSJzdGRpbiIKCV0sCgkibmFtZXMiOiBbXSwKCSJtYXBwaW5ncyI6ICJBQUlBLEFBQUEsSUFBSSxDQUFDO0VBQ0gsSUFBSSxFQUFFLElBQUksQ0FKQyxTQUFTLEVBQUUsVUFBVTtFQUtoQyxLQUFLLEVBSlMsSUFBSTtFQUtsQixLQUFLLEVBQUUsVUFBVSxHQUNsQiIKfQ== */}} 1 {expected boolean value but got "x"}} 335 | 336 | ############################################################################### 337 | 338 | test sass-4.7 {option source_map_contents (bool)} -body { 339 | list [catch { 340 | sass compile -options [list source_map_contents true] $scss(2) 341 | } errMsg] $errMsg [catch { 342 | sass compile -options [list source_map_contents x] $scss(2) 343 | } errMsg] $errMsg 344 | } -cleanup { 345 | unset -nocomplain errMsg 346 | } -result {0 {errorStatus 0 outputString {body { 347 | font: 100% Helvetica, sans-serif; 348 | color: #333; 349 | width: 31.123456%; } 350 | }} 1 {expected boolean value but got "x"}} 351 | 352 | ############################################################################### 353 | 354 | test sass-4.8 {option omit_source_map_url (bool)} -body { 355 | list [catch { 356 | sass compile -options [list omit_source_map_url true] $scss(2) 357 | } errMsg] $errMsg [catch { 358 | sass compile -options [list omit_source_map_url x] $scss(2) 359 | } errMsg] $errMsg 360 | } -cleanup { 361 | unset -nocomplain errMsg 362 | } -result {0 {errorStatus 0 outputString {body { 363 | font: 100% Helvetica, sans-serif; 364 | color: #333; 365 | width: 31.123456%; } 366 | }} 1 {expected boolean value but got "x"}} 367 | 368 | ############################################################################### 369 | 370 | test sass-4.9 {option is_indented_syntax_src (bool)} -body { 371 | list [catch { 372 | sass compile -options [list is_indented_syntax_src true] $scss(2) 373 | } errMsg] $errMsg [catch { 374 | sass compile -options [list is_indented_syntax_src x] $scss(2) 375 | } errMsg] $errMsg 376 | } -cleanup { 377 | unset -nocomplain errMsg 378 | } -result {0 {errorStatus 1 errorMessage Error:\ Invalid\ CSS\ after\ \"body\ \{\":\ expected\ \"\}\",\ was\ \"\{\"\n\ \ \ \ \ \ \ \ on\ line\ 5\ of\ stdin\n>>\ body\ \{\ \{\n\ \ \ ------^\n errorLine 5 errorColumn 7} 1 {expected boolean value but got "x"}} 379 | 380 | ############################################################################### 381 | 382 | test sass-4.10 {option indent (string)} -body { 383 | list [catch { 384 | sass compile -options [list indent **] $scss(2) 385 | } errMsg] $errMsg 386 | } -cleanup { 387 | unset -nocomplain errMsg 388 | } -result {0 {errorStatus 0 outputString {body { 389 | **font: 100% Helvetica, sans-serif; 390 | **color: #333; 391 | **width: 31.123456%; } 392 | }}} 393 | 394 | ############################################################################### 395 | 396 | test sass-4.11 {option linefeed (string)} -body { 397 | list [catch { 398 | sass compile -options [list linefeed **] $scss(2) 399 | } errMsg] $errMsg 400 | } -cleanup { 401 | unset -nocomplain errMsg 402 | } -result {0 {errorStatus 0 outputString {body {** font: 100% Helvetica,\ 403 | sans-serif;** color: #333;** width: 31.123456%; }**}}} 404 | 405 | ############################################################################### 406 | 407 | test sass-4.12 {option input_path (string)} -body { 408 | list [catch { 409 | sass compile -options [list input_path $path] $scss(2) 410 | } errMsg] $errMsg [catch { 411 | sass compile -options [list input_path ""] $scss(2) 412 | } errMsg] $errMsg 413 | } -cleanup { 414 | unset -nocomplain errMsg 415 | } -result {0 {errorStatus 0 outputString {body { 416 | font: 100% Helvetica, sans-serif; 417 | color: #333; 418 | width: 31.123456%; } 419 | }} 0 {errorStatus 0 outputString {body { 420 | font: 100% Helvetica, sans-serif; 421 | color: #333; 422 | width: 31.123456%; } 423 | }}} 424 | 425 | ############################################################################### 426 | 427 | test sass-4.13 {option output_path (string)} -body { 428 | list [catch { 429 | sass compile -options [list output_path $path] $scss(2) 430 | } errMsg] $errMsg [catch { 431 | sass compile -options [list output_path ""] $scss(2) 432 | } errMsg] $errMsg 433 | } -cleanup { 434 | unset -nocomplain errMsg 435 | } -result {0 {errorStatus 0 outputString {body { 436 | font: 100% Helvetica, sans-serif; 437 | color: #333; 438 | width: 31.123456%; } 439 | }} 0 {errorStatus 0 outputString {body { 440 | font: 100% Helvetica, sans-serif; 441 | color: #333; 442 | width: 31.123456%; } 443 | }}} 444 | 445 | ############################################################################### 446 | 447 | # 448 | # NOTE: The function associated with this option was removed from "libsass" 449 | # in a recent commit, see: 450 | # 451 | # https://github.com/sass/libsass/commit/c82c82bf6f 452 | # 453 | # The "image_path" option itself is being retained; however, it will 454 | # always raise a script error. 455 | # 456 | test sass-4.14 {option image_path (string)} -body { 457 | list [catch { 458 | sass compile -options [list image_path $path] $scss(2) 459 | } errMsg] $errMsg [catch { 460 | sass compile -options [list image_path ""] $scss(2) 461 | } errMsg] $errMsg 462 | } -cleanup { 463 | unset -nocomplain errMsg 464 | } -result {1 {option "image_path" has no setter} 1 {option "image_path" has no\ 465 | setter}} 466 | 467 | ############################################################################### 468 | 469 | test sass-4.15 {option include_path (string)} -body { 470 | list [catch { 471 | sass compile -options [list include_path $path] $scss(2) 472 | } errMsg] $errMsg [catch { 473 | sass compile -options [list include_path ""] $scss(2) 474 | } errMsg] $errMsg 475 | } -cleanup { 476 | unset -nocomplain errMsg 477 | } -result {0 {errorStatus 0 outputString {body { 478 | font: 100% Helvetica, sans-serif; 479 | color: #333; 480 | width: 31.123456%; } 481 | }} 0 {errorStatus 0 outputString {body { 482 | font: 100% Helvetica, sans-serif; 483 | color: #333; 484 | width: 31.123456%; } 485 | }}} 486 | 487 | ############################################################################### 488 | 489 | test sass-4.16 {option source_map_file (string)} -body { 490 | list [catch { 491 | sass compile -options [list source_map_file [file join \ 492 | [getTempPath] sass-4.16.map]] $scss(2) 493 | } errMsg] $errMsg [catch { 494 | sass compile -options [list source_map_file ""] $scss(2) 495 | } errMsg] $errMsg 496 | } -cleanup { 497 | unset -nocomplain errMsg 498 | } -match regexp -result {^0 \{errorStatus 0 outputString \{body \{ 499 | font: 100% Helvetica, sans-serif; 500 | color: #333; 501 | width: 31\.123456%; \} 502 | 503 | /\*# sourceMappingURL=(?:.*?)/sass-4\.16\.map \*/\} sourceMapString \{\{ 504 | "version": 3, 505 | "file": "(?:.*?)", 506 | "sources": \[ 507 | "(?:.*?)" 508 | \], 509 | "names": \[\], 510 | "mappings": "(?:.*?)" 511 | \}\}\} 0 \{errorStatus 0 outputString \{body \{ 512 | font: 100% Helvetica, sans-serif; 513 | color: #333; 514 | width: 31\.123456%; \} 515 | \}\}$} 516 | 517 | ############################################################################### 518 | 519 | unset -nocomplain scss path 520 | 521 | # cleanup 522 | ::tcltest::cleanupTests 523 | return 524 | -------------------------------------------------------------------------------- /generic/tclsass.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tclsass.c -- Tcl Package for libsass 3 | * 4 | * Written by Joe Mistachkin. 5 | * 6 | * See the file "license.terms" for information on usage and redistribution of 7 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. 8 | */ 9 | 10 | #include /* NOTE: For free(). */ 11 | #include /* NOTE: For strlen(), strcmp(), strdup(). */ 12 | #include "tcl.h" /* NOTE: For public Tcl API. */ 13 | #include "sass/context.h" /* NOTE: For public libsass API. */ 14 | #include "pkgVersion.h" /* NOTE: Package version information. */ 15 | #include "tclsassInt.h" /* NOTE: For private package API. */ 16 | #include "tclsass.h" /* NOTE: For public package API. */ 17 | 18 | /* 19 | * NOTE: These are the types of Sass contexts supported by the [sass compile] 20 | * sub-command. They are used to process the -type option. The values 21 | * were stolen from the Sass_Input_Style enumeration within the libsass 22 | * source code file "sass_context.cpp". 23 | */ 24 | 25 | enum Sass_Context_Type { 26 | SASS_CONTEXT_NULL, 27 | SASS_CONTEXT_FILE, 28 | SASS_CONTEXT_DATA, 29 | SASS_CONTEXT_FOLDER 30 | }; 31 | 32 | /* 33 | * NOTE: Private functions defined in this file. 34 | */ 35 | 36 | static int GetStringFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, 37 | int *pLength, char **pzValue); 38 | static int GetContextTypeFromObj(Tcl_Interp *interp, 39 | Tcl_Obj *objPtr, enum Sass_Context_Type *typePtr); 40 | static int GetOutputStyleFromObj(Tcl_Interp *interp, 41 | Tcl_Obj *objPtr, enum Sass_Output_Style *stylePtr); 42 | static int FindAndSetContextOption(Tcl_Interp *interp, 43 | int nameLength, const char *zName, Tcl_Obj *objPtr, 44 | struct Sass_Options *optsPtr); 45 | static int ProcessContextOptions(Tcl_Interp *interp, int objc, 46 | Tcl_Obj *CONST objv[], int *idxPtr, 47 | enum Sass_Context_Type *typePtr, 48 | struct Sass_Options *optsPtr); 49 | static int SetResultFromContext(Tcl_Interp *interp, 50 | struct Sass_Context *ctxPtr); 51 | static int CompileForType(Tcl_Interp *interp, 52 | enum Sass_Context_Type type, 53 | struct Sass_Options **pOptsPtr, 54 | const char* zSource); 55 | static void SassExitProc(ClientData clientData); 56 | static int SassObjCmd(ClientData clientData, Tcl_Interp *interp, 57 | int objc, Tcl_Obj *CONST objv[]); 58 | static void SassObjCmdDeleteProc(ClientData clientData); 59 | 60 | /* 61 | *---------------------------------------------------------------------- 62 | * 63 | * GetStringFromObj -- 64 | * 65 | * This function attempts to get the string representation of the 66 | * specified Tcl object. Then, it validates that the returned 67 | * string pointer and length. 68 | * 69 | * Results: 70 | * A standard Tcl result. 71 | * 72 | * Side effects: 73 | * None. 74 | * 75 | *---------------------------------------------------------------------- 76 | */ 77 | 78 | static int GetStringFromObj( 79 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 80 | Tcl_Obj *objPtr, /* IN: The source object. */ 81 | int *pLength, /* OUT: Length of the string. */ 82 | char **pzValue) /* OUT: The string value. */ 83 | { 84 | if (interp == NULL) { 85 | PACKAGE_TRACE(("GetStringFromObj: no Tcl interpreter\n")); 86 | return TCL_ERROR; 87 | } 88 | 89 | if (objPtr == NULL) { 90 | Tcl_AppendResult(interp, "no string object\n", NULL); 91 | return TCL_ERROR; 92 | } 93 | 94 | if (pLength == NULL) { 95 | Tcl_AppendResult(interp, "no string length pointer\n", NULL); 96 | return TCL_ERROR; 97 | } 98 | 99 | if (pzValue == NULL) { 100 | Tcl_AppendResult(interp, "no string pointer\n", NULL); 101 | return TCL_ERROR; 102 | } 103 | 104 | *pzValue = Tcl_GetStringFromObj(objPtr, pLength); 105 | 106 | if ((*pzValue == NULL) || (*pLength < 0)) { 107 | Tcl_AppendResult(interp, "bad string or length\n", NULL); 108 | return TCL_ERROR; 109 | } 110 | 111 | return TCL_OK; 112 | } 113 | 114 | /* 115 | *---------------------------------------------------------------------- 116 | * 117 | * GetContextTypeFromObj -- 118 | * 119 | * This function attempts to convert a string context type name 120 | * into an actual Sass_Context_Type value. The valid values for 121 | * the string context type name are: 122 | * 123 | * data 124 | * file 125 | * 126 | * If the string context type name does not conform to one of the 127 | * above values, it will be rejected and a script error will be 128 | * generated. 129 | * 130 | * Results: 131 | * A standard Tcl result. 132 | * 133 | * Side effects: 134 | * None. 135 | * 136 | *---------------------------------------------------------------------- 137 | */ 138 | 139 | static int GetContextTypeFromObj( 140 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 141 | Tcl_Obj *objPtr, /* The string to convert. */ 142 | enum Sass_Context_Type *typePtr) /* OUT: The context type. */ 143 | { 144 | int code; 145 | int typeLength; 146 | char *zType; 147 | 148 | if (interp == NULL) { 149 | PACKAGE_TRACE(("GetContextTypeFromObj: no Tcl interpreter\n")); 150 | return TCL_ERROR; 151 | } 152 | 153 | if (objPtr == NULL) { 154 | Tcl_AppendResult(interp, "no context type object\n", NULL); 155 | return TCL_ERROR; 156 | } 157 | 158 | if (typePtr == NULL) { 159 | Tcl_AppendResult(interp, "no context type pointer\n", NULL); 160 | return TCL_ERROR; 161 | } 162 | 163 | code = GetStringFromObj(interp, objPtr, &typeLength, &zType); 164 | 165 | if (code != TCL_OK) 166 | return code; 167 | 168 | if (CheckString(typeLength, zType, "data")) { 169 | *typePtr = SASS_CONTEXT_DATA; 170 | return TCL_OK; 171 | } 172 | 173 | if (CheckString(typeLength, zType, "file")) { 174 | *typePtr = SASS_CONTEXT_FILE; 175 | return TCL_OK; 176 | } 177 | 178 | Tcl_AppendResult(interp, 179 | "unsupported context type, must be: data or file\n", NULL); 180 | 181 | return TCL_ERROR; 182 | } 183 | 184 | /* 185 | *---------------------------------------------------------------------- 186 | * 187 | * GetOutputStyleFromObj -- 188 | * 189 | * This function attempts to convert a string output style name 190 | * into an actual Sass_Output_Style value. The valid values for 191 | * the string output style name are: 192 | * 193 | * nested 194 | * expanded 195 | * compact 196 | * compressed 197 | * 198 | * If the string output style name does not conform to one of the 199 | * above values, it will be rejected and a script error will be 200 | * generated. 201 | * 202 | * Results: 203 | * A standard Tcl result. 204 | * 205 | * Side effects: 206 | * None. 207 | * 208 | *---------------------------------------------------------------------- 209 | */ 210 | 211 | static int GetOutputStyleFromObj( 212 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 213 | Tcl_Obj *objPtr, /* The string to convert. */ 214 | enum Sass_Output_Style *stylePtr) /* OUT: The output style. */ 215 | { 216 | int code; 217 | int styleLength; 218 | char *zStyle; 219 | 220 | if (interp == NULL) { 221 | PACKAGE_TRACE(("GetOutputStyleFromObj: no Tcl interpreter\n")); 222 | return TCL_ERROR; 223 | } 224 | 225 | if (objPtr == NULL) { 226 | Tcl_AppendResult(interp, "no output style object\n", NULL); 227 | return TCL_ERROR; 228 | } 229 | 230 | if (stylePtr == NULL) { 231 | Tcl_AppendResult(interp, "no output style pointer\n", NULL); 232 | return TCL_ERROR; 233 | } 234 | 235 | code = GetStringFromObj(interp, objPtr, &styleLength, &zStyle); 236 | 237 | if (code != TCL_OK) 238 | return code; 239 | 240 | if (CheckString(styleLength, zStyle, "nested")) { 241 | *stylePtr = SASS_STYLE_NESTED; 242 | return TCL_OK; 243 | } 244 | 245 | if (CheckString(styleLength, zStyle, "expanded")) { 246 | *stylePtr = SASS_STYLE_EXPANDED; 247 | return TCL_OK; 248 | } 249 | 250 | if (CheckString(styleLength, zStyle, "compact")) { 251 | *stylePtr = SASS_STYLE_COMPACT; 252 | return TCL_OK; 253 | } 254 | 255 | if (CheckString(styleLength, zStyle, "compressed")) { 256 | *stylePtr = SASS_STYLE_COMPRESSED; 257 | return TCL_OK; 258 | } 259 | 260 | Tcl_AppendResult(interp, 261 | "unsupported output style, must be: nested, expanded, compact, " 262 | "or compressed\n", NULL); 263 | 264 | return TCL_ERROR; 265 | } 266 | 267 | /* 268 | *---------------------------------------------------------------------- 269 | * 270 | * FindAndSetContextOption -- 271 | * 272 | * This function attempts to locate the specified Sass context 273 | * option and set its value based on the specified Tcl object. 274 | * 275 | * Results: 276 | * A standard Tcl result. 277 | * 278 | * Side effects: 279 | * None. 280 | * 281 | *---------------------------------------------------------------------- 282 | */ 283 | 284 | static int FindAndSetContextOption( 285 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 286 | int nameLength, /* IN: Length of option name. */ 287 | const char *zName, /* IN: The option name. */ 288 | Tcl_Obj *objPtr, /* IN: The option value. */ 289 | struct Sass_Options *optsPtr) /* IN/OUT: The context options. */ 290 | { 291 | static struct sOptions { 292 | const char *zName; /* Name of the option. */ 293 | fn_get_any *xGetValue; /* Tcl C API to get value. */ 294 | fn_set_any *xSetOption; /* Sass C API to set value. */ 295 | } aOptions[] = {{ 296 | /* zName: */ "precision", 297 | /* xGetValue: */ NULL, 298 | /* xSetOption: */ NULL 299 | }, { 300 | /* zName: */ "output_style", 301 | /* xGetValue: */ NULL, 302 | /* xSetOption: */ NULL 303 | }, { 304 | /* zName: */ "source_comments", 305 | /* xGetValue: */ NULL, 306 | /* xSetOption: */ NULL 307 | }, { 308 | /* zName: */ "source_map_embed", 309 | /* xGetValue: */ NULL, 310 | /* xSetOption: */ NULL 311 | }, { 312 | /* zName: */ "source_map_contents", 313 | /* xGetValue: */ NULL, 314 | /* xSetOption: */ NULL 315 | }, { 316 | /* zName: */ "omit_source_map_url", 317 | /* xGetValue: */ NULL, 318 | /* xSetOption: */ NULL 319 | }, { 320 | /* zName: */ "is_indented_syntax_src", 321 | /* xGetValue: */ NULL, 322 | /* xSetOption: */ NULL 323 | }, { 324 | /* zName: */ "indent", 325 | /* xGetValue: */ NULL, 326 | /* xSetOption: */ NULL 327 | }, { 328 | /* zName: */ "linefeed", 329 | /* xGetValue: */ NULL, 330 | /* xSetOption: */ NULL 331 | }, { 332 | /* zName: */ "input_path", 333 | /* xGetValue: */ NULL, 334 | /* xSetOption: */ NULL 335 | }, { 336 | /* zName: */ "output_path", 337 | /* xGetValue: */ NULL, 338 | /* xSetOption: */ NULL 339 | }, { 340 | /* zName: */ "image_path", 341 | /* xGetValue: */ NULL, 342 | /* xSetOption: */ NULL 343 | }, { 344 | /* zName: */ "include_path", 345 | /* xGetValue: */ NULL, 346 | /* xSetOption: */ NULL 347 | }, { 348 | /* zName: */ "source_map_file", 349 | /* xGetValue: */ NULL, 350 | /* xSetOption: */ NULL 351 | }}; 352 | 353 | int code = TCL_ERROR; 354 | int bFound = 0; 355 | Tcl_Obj *namesPtr; 356 | int index; 357 | 358 | if (interp == NULL) { 359 | PACKAGE_TRACE(("FindAndSetContextOption: no Tcl interpreter\n")); 360 | return TCL_ERROR; 361 | } 362 | 363 | if (zName == NULL) { 364 | Tcl_AppendResult(interp, "no option name\n", NULL); 365 | return TCL_ERROR; 366 | } 367 | 368 | if (objPtr == NULL) { 369 | Tcl_AppendResult(interp, "no option value\n", NULL); 370 | return TCL_ERROR; 371 | } 372 | 373 | if (optsPtr == NULL) { 374 | Tcl_AppendResult(interp, "no options pointer\n", NULL); 375 | return TCL_ERROR; 376 | } 377 | 378 | aOptions[0].xGetValue = (fn_get_any *)Tcl_GetIntFromObj; 379 | aOptions[0].xSetOption = (fn_set_any *)sass_option_set_precision; 380 | aOptions[1].xGetValue = (fn_get_any *)GetOutputStyleFromObj; 381 | aOptions[1].xSetOption = (fn_set_any *)sass_option_set_output_style; 382 | aOptions[2].xGetValue = (fn_get_any *)Tcl_GetBooleanFromObj; 383 | aOptions[2].xSetOption = (fn_set_any *)sass_option_set_source_comments; 384 | aOptions[3].xGetValue = (fn_get_any *)Tcl_GetBooleanFromObj; 385 | aOptions[3].xSetOption = (fn_set_any *)sass_option_set_source_map_embed; 386 | aOptions[4].xGetValue = (fn_get_any *)Tcl_GetBooleanFromObj; 387 | aOptions[4].xSetOption = (fn_set_any *)sass_option_set_source_map_contents; 388 | aOptions[5].xGetValue = (fn_get_any *)Tcl_GetBooleanFromObj; 389 | aOptions[5].xSetOption = (fn_set_any *)sass_option_set_omit_source_map_url; 390 | aOptions[6].xGetValue = (fn_get_any *)Tcl_GetBooleanFromObj; 391 | aOptions[6].xSetOption = (fn_set_any *)sass_option_set_is_indented_syntax_src; 392 | aOptions[7].xGetValue = (fn_get_any *)GetStringFromObj; 393 | aOptions[7].xSetOption = (fn_set_any *)sass_option_set_indent; 394 | aOptions[8].xGetValue = (fn_get_any *)GetStringFromObj; 395 | aOptions[8].xSetOption = (fn_set_any *)sass_option_set_linefeed; 396 | aOptions[9].xGetValue = (fn_get_any *)GetStringFromObj; 397 | aOptions[9].xSetOption = (fn_set_any *)sass_option_set_input_path; 398 | aOptions[10].xGetValue = (fn_get_any *)GetStringFromObj; 399 | aOptions[10].xSetOption = (fn_set_any *)sass_option_set_output_path; 400 | aOptions[11].xGetValue = (fn_get_any *)GetStringFromObj; 401 | aOptions[11].xSetOption = (fn_set_any *)NULL; 402 | aOptions[12].xGetValue = (fn_get_any *)GetStringFromObj; 403 | aOptions[12].xSetOption = (fn_set_any *)sass_option_set_include_path; 404 | aOptions[13].xGetValue = (fn_get_any *)GetStringFromObj; 405 | aOptions[13].xSetOption = (fn_set_any *)sass_option_set_source_map_file; 406 | 407 | namesPtr = Tcl_NewObj(); 408 | 409 | if (namesPtr == NULL) { 410 | Tcl_AppendResult(interp, "out of memory: namesPtr\n", NULL); 411 | return TCL_ERROR; 412 | } 413 | 414 | Tcl_IncrRefCount(namesPtr); 415 | 416 | for (index = 0; index < ArraySize(aOptions); index++) { 417 | if (CheckString(nameLength, zName, aOptions[index].zName)) { 418 | fn_get_any *xGetValue = aOptions[index].xGetValue; 419 | fn_set_any *xSetOption = aOptions[index].xSetOption; 420 | 421 | if (xGetValue == Tcl_GetBooleanFromObj) { 422 | int iValue; 423 | 424 | if (xGetValue(interp, objPtr, &iValue) == TCL_OK) { 425 | if (xSetOption != NULL) { 426 | xSetOption(optsPtr, (bool)iValue); 427 | code = TCL_OK; 428 | } else { 429 | Tcl_AppendResult(interp, 430 | "option \"", zName, "\" has no setter", NULL); 431 | } 432 | } 433 | } else if (xGetValue == Tcl_GetIntFromObj) { 434 | int iValue; 435 | 436 | if (xGetValue(interp, objPtr, &iValue) == TCL_OK) { 437 | if (xSetOption != NULL) { 438 | xSetOption(optsPtr, iValue); 439 | code = TCL_OK; 440 | } else { 441 | Tcl_AppendResult(interp, 442 | "option \"", zName, "\" has no setter", NULL); 443 | } 444 | } 445 | } else if (xGetValue == GetOutputStyleFromObj) { 446 | enum Sass_Output_Style eValue; 447 | 448 | if (xGetValue(interp, objPtr, &eValue) == TCL_OK) { 449 | if (xSetOption != NULL) { 450 | xSetOption(optsPtr, eValue); 451 | code = TCL_OK; 452 | } else { 453 | Tcl_AppendResult(interp, 454 | "option \"", zName, "\" has no setter", NULL); 455 | } 456 | } 457 | } else if (xGetValue == GetStringFromObj) { 458 | int valueLength; 459 | char *zValue; 460 | 461 | if (xGetValue(interp, objPtr, &valueLength, 462 | &zValue) == TCL_OK) { 463 | if (xSetOption != NULL) { 464 | xSetOption(optsPtr, zValue); 465 | code = TCL_OK; 466 | } else { 467 | Tcl_AppendResult(interp, 468 | "option \"", zName, "\" has no setter", NULL); 469 | } 470 | } 471 | } else { 472 | Tcl_AppendResult(interp, "unsupported option type\n", NULL); 473 | } 474 | 475 | bFound = 1; 476 | break; 477 | } else { 478 | if (index > 0) { 479 | Tcl_AppendToObj(namesPtr, ", ", -1); 480 | } 481 | 482 | if (index == ArraySize(aOptions) - 1) { 483 | Tcl_AppendToObj(namesPtr, "or ", -1); 484 | } 485 | 486 | Tcl_AppendToObj(namesPtr, aOptions[index].zName, -1); 487 | } 488 | } 489 | 490 | if (!bFound) { 491 | Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); 492 | 493 | if (resultPtr != NULL) { 494 | Tcl_AppendToObj(resultPtr, "unknown option, must be: ", -1); 495 | Tcl_AppendObjToObj(resultPtr, namesPtr); 496 | Tcl_AppendToObj(resultPtr, "\n", -1); 497 | } 498 | } 499 | 500 | Tcl_DecrRefCount(namesPtr); 501 | return code; 502 | } 503 | 504 | /* 505 | *---------------------------------------------------------------------- 506 | * 507 | * ProcessContextOptions -- 508 | * 509 | * This function processes options supported by the [sass compile] 510 | * sub-command. If an option does not coform to the expected type 511 | * -OR- an unknown option is encountered, a script error will be 512 | * generated. All valid options, except -type, are processed by 513 | * setting the appropriate field within the Sass_Options struct, 514 | * using the public API. The -type option is handled by processing 515 | * the resulting Sass_Context_Type into the provided value pointer. 516 | * The first option argument index to check is queried from the 517 | * idxPtr argument. Furthermore, the first non-option argument 518 | * index after all options are processed will be stored into the 519 | * idxPtr argument, if applicable. If there are no more arguments 520 | * after processing the options, a value of -1 will be stored. 521 | * 522 | * Results: 523 | * A standard Tcl result. 524 | * 525 | * Side effects: 526 | * None. 527 | * 528 | *---------------------------------------------------------------------- 529 | */ 530 | 531 | static int ProcessContextOptions( 532 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 533 | int objc, /* Number of arguments. */ 534 | Tcl_Obj *CONST objv[], /* The array of arguments. */ 535 | int *idxPtr, /* IN/OUT: 1st [non-]option argument. */ 536 | enum Sass_Context_Type *typePtr, /* OUT: The context type. */ 537 | struct Sass_Options *optsPtr) /* IN/OUT: The context options. */ 538 | { 539 | int index; 540 | 541 | if (interp == NULL) { 542 | PACKAGE_TRACE(("ProcessContextOptions: no Tcl interpreter\n")); 543 | return TCL_ERROR; 544 | } 545 | 546 | if (objv == NULL) { 547 | Tcl_AppendResult(interp, "no arguments array\n", NULL); 548 | return TCL_ERROR; 549 | } 550 | 551 | if (idxPtr == NULL) { 552 | Tcl_AppendResult(interp, "no argument index pointer\n", NULL); 553 | return TCL_ERROR; 554 | } 555 | 556 | if (typePtr == NULL) { 557 | Tcl_AppendResult(interp, "no context type pointer\n", NULL); 558 | return TCL_ERROR; 559 | } 560 | 561 | if (optsPtr == NULL) { 562 | Tcl_AppendResult(interp, "no options pointer\n", NULL); 563 | return TCL_ERROR; 564 | } 565 | 566 | *typePtr = SASS_CONTEXT_DATA; /* TODO: Good default? */ 567 | 568 | for (index = *idxPtr; index < objc; index++) { 569 | int code; 570 | int argLength; 571 | char *zArg; 572 | 573 | if (objv[index] == NULL) { 574 | Tcl_AppendResult(interp, "no argument object\n", NULL); 575 | return TCL_ERROR; 576 | } 577 | 578 | code = GetStringFromObj(interp, objv[index], &argLength, &zArg); 579 | 580 | if (code != TCL_OK) 581 | return code; 582 | 583 | if (CheckString(argLength, zArg, "--")) { 584 | index++; 585 | 586 | *idxPtr = (index < objc) ? index : -1; 587 | return TCL_OK; 588 | } 589 | 590 | if (CheckString(argLength, zArg, "-type")) { 591 | index++; 592 | 593 | if (index >= objc) { 594 | Tcl_AppendResult(interp, "missing context type\n", NULL); 595 | return TCL_ERROR; 596 | } 597 | 598 | if (GetContextTypeFromObj(interp, objv[index], typePtr) != TCL_OK) { 599 | return TCL_ERROR; 600 | } 601 | 602 | continue; 603 | } 604 | 605 | if (CheckString(argLength, zArg, "-options")) { 606 | int dictObjc; 607 | Tcl_Obj **dictObjv; 608 | int dictIndex; 609 | 610 | index++; 611 | 612 | if (index >= objc) { 613 | Tcl_AppendResult(interp, "missing options dictionary\n", NULL); 614 | return TCL_ERROR; 615 | } 616 | 617 | if (Tcl_ListObjGetElements(interp, objv[index], &dictObjc, 618 | &dictObjv) != TCL_OK) { 619 | return TCL_ERROR; 620 | } 621 | 622 | if ((dictObjc % 2) != 0) { 623 | Tcl_AppendResult(interp, "malformed dictionary\n", NULL); 624 | return TCL_ERROR; 625 | } 626 | 627 | for (dictIndex = 0; dictIndex < dictObjc; dictIndex += 2) { 628 | int nameLength; 629 | char *zName; 630 | 631 | code = GetStringFromObj(interp, dictObjv[dictIndex], 632 | &nameLength, &zName); 633 | 634 | if (code != TCL_OK) 635 | return code; 636 | 637 | code = FindAndSetContextOption(interp, nameLength, zName, 638 | dictObjv[dictIndex + 1], optsPtr); 639 | 640 | if (code != TCL_OK) 641 | return code; 642 | } 643 | 644 | continue; 645 | } 646 | 647 | *idxPtr = index; 648 | return TCL_OK; 649 | } 650 | 651 | *idxPtr = -1; 652 | return TCL_OK; 653 | } 654 | 655 | /* 656 | *---------------------------------------------------------------------- 657 | * 658 | * SetResultFromContext -- 659 | * 660 | * This function quries the specified Sass_Context and uses the 661 | * error status and output string to modify the result of the Tcl 662 | * interpreter. 663 | * 664 | * Results: 665 | * A standard Tcl result. 666 | * 667 | * Side effects: 668 | * None. 669 | * 670 | *---------------------------------------------------------------------- 671 | */ 672 | 673 | static int SetResultFromContext( 674 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 675 | struct Sass_Context *ctxPtr) /* IN: Get status/result from here. */ 676 | { 677 | int code; 678 | int rc; 679 | struct Sass_Options *optsPtr; 680 | const char *zSourceMapFile; 681 | Tcl_Obj *listPtr = NULL; 682 | Tcl_Obj *objPtr; 683 | 684 | if (interp == NULL) { 685 | PACKAGE_TRACE(("SetResultFromContext: no Tcl interpreter\n")); 686 | return TCL_ERROR; 687 | } 688 | 689 | if (ctxPtr == NULL) { 690 | Tcl_AppendResult(interp, "no context\n", NULL); 691 | return TCL_ERROR; 692 | } 693 | 694 | listPtr = Tcl_NewListObj(0, NULL); 695 | 696 | if (listPtr == NULL) { 697 | Tcl_AppendResult(interp, "out of memory: listPtr\n", NULL); 698 | code = TCL_ERROR; 699 | goto done; 700 | } 701 | 702 | Tcl_IncrRefCount(listPtr); 703 | objPtr = Tcl_NewStringObj("errorStatus", -1); 704 | 705 | if (objPtr == NULL) { 706 | Tcl_AppendResult(interp, "out of memory: errorStatus1\n", NULL); 707 | code = TCL_ERROR; 708 | goto done; 709 | } 710 | 711 | Tcl_IncrRefCount(objPtr); 712 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 713 | Tcl_DecrRefCount(objPtr); 714 | 715 | if (code != TCL_OK) 716 | goto done; 717 | 718 | rc = sass_context_get_error_status(ctxPtr); 719 | objPtr = Tcl_NewIntObj(rc); 720 | 721 | if (objPtr == NULL) { 722 | Tcl_AppendResult(interp, "out of memory: errorStatus2\n", NULL); 723 | code = TCL_ERROR; 724 | goto done; 725 | } 726 | 727 | Tcl_IncrRefCount(objPtr); 728 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 729 | Tcl_DecrRefCount(objPtr); 730 | 731 | if (code != TCL_OK) 732 | goto done; 733 | 734 | if (rc == 0) { 735 | objPtr = Tcl_NewStringObj("outputString", -1); 736 | 737 | if (objPtr == NULL) { 738 | Tcl_AppendResult(interp, "out of memory: outputString1\n", NULL); 739 | code = TCL_ERROR; 740 | goto done; 741 | } 742 | 743 | Tcl_IncrRefCount(objPtr); 744 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 745 | Tcl_DecrRefCount(objPtr); 746 | 747 | if (code != TCL_OK) 748 | goto done; 749 | 750 | objPtr = Tcl_NewStringObj(sass_context_get_output_string(ctxPtr), -1); 751 | 752 | if (objPtr == NULL) { 753 | Tcl_AppendResult(interp, "out of memory: outputString2\n", NULL); 754 | code = TCL_ERROR; 755 | goto done; 756 | } 757 | 758 | Tcl_IncrRefCount(objPtr); 759 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 760 | Tcl_DecrRefCount(objPtr); 761 | 762 | if (code != TCL_OK) 763 | goto done; 764 | 765 | optsPtr = sass_context_get_options(ctxPtr); 766 | 767 | zSourceMapFile = (optsPtr != NULL) ? 768 | sass_option_get_source_map_file(optsPtr) : NULL; 769 | 770 | if ((zSourceMapFile != NULL) && (strlen(zSourceMapFile) > 0)) { 771 | objPtr = Tcl_NewStringObj("sourceMapString", -1); 772 | 773 | if (objPtr == NULL) { 774 | Tcl_AppendResult(interp, 775 | "out of memory: sourceMapString1\n", NULL); 776 | 777 | code = TCL_ERROR; 778 | goto done; 779 | } 780 | 781 | Tcl_IncrRefCount(objPtr); 782 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 783 | Tcl_DecrRefCount(objPtr); 784 | 785 | if (code != TCL_OK) 786 | goto done; 787 | 788 | objPtr = Tcl_NewStringObj( 789 | sass_context_get_source_map_string(ctxPtr), -1); 790 | 791 | if (objPtr == NULL) { 792 | Tcl_AppendResult(interp, 793 | "out of memory: sourceMapString2\n", NULL); 794 | 795 | code = TCL_ERROR; 796 | goto done; 797 | } 798 | 799 | Tcl_IncrRefCount(objPtr); 800 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 801 | Tcl_DecrRefCount(objPtr); 802 | 803 | if (code != TCL_OK) 804 | goto done; 805 | } 806 | } else { 807 | objPtr = Tcl_NewStringObj("errorMessage", -1); 808 | 809 | if (objPtr == NULL) { 810 | Tcl_AppendResult(interp, "out of memory: errorMessage1\n", NULL); 811 | code = TCL_ERROR; 812 | goto done; 813 | } 814 | 815 | Tcl_IncrRefCount(objPtr); 816 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 817 | Tcl_DecrRefCount(objPtr); 818 | 819 | if (code != TCL_OK) 820 | goto done; 821 | 822 | objPtr = Tcl_NewStringObj(sass_context_get_error_message(ctxPtr), -1); 823 | 824 | if (objPtr == NULL) { 825 | Tcl_AppendResult(interp, "out of memory: errorMessage2\n", NULL); 826 | code = TCL_ERROR; 827 | goto done; 828 | } 829 | 830 | Tcl_IncrRefCount(objPtr); 831 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 832 | Tcl_DecrRefCount(objPtr); 833 | 834 | if (code != TCL_OK) 835 | goto done; 836 | 837 | objPtr = Tcl_NewStringObj("errorLine", -1); 838 | 839 | if (objPtr == NULL) { 840 | Tcl_AppendResult(interp, "out of memory: errorLine1\n", NULL); 841 | code = TCL_ERROR; 842 | goto done; 843 | } 844 | 845 | Tcl_IncrRefCount(objPtr); 846 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 847 | Tcl_DecrRefCount(objPtr); 848 | 849 | if (code != TCL_OK) 850 | goto done; 851 | 852 | objPtr = Tcl_NewWideIntObj(sass_context_get_error_line(ctxPtr)); 853 | 854 | if (objPtr == NULL) { 855 | Tcl_AppendResult(interp, "out of memory: errorLine2\n", NULL); 856 | code = TCL_ERROR; 857 | goto done; 858 | } 859 | 860 | Tcl_IncrRefCount(objPtr); 861 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 862 | Tcl_DecrRefCount(objPtr); 863 | 864 | if (code != TCL_OK) 865 | goto done; 866 | 867 | objPtr = Tcl_NewStringObj("errorColumn", -1); 868 | 869 | if (objPtr == NULL) { 870 | Tcl_AppendResult(interp, "out of memory: errorColumn1\n", NULL); 871 | code = TCL_ERROR; 872 | goto done; 873 | } 874 | 875 | Tcl_IncrRefCount(objPtr); 876 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 877 | Tcl_DecrRefCount(objPtr); 878 | 879 | if (code != TCL_OK) 880 | goto done; 881 | 882 | objPtr = Tcl_NewWideIntObj(sass_context_get_error_column(ctxPtr)); 883 | 884 | if (objPtr == NULL) { 885 | Tcl_AppendResult(interp, "out of memory: errorColumn2\n", NULL); 886 | code = TCL_ERROR; 887 | goto done; 888 | } 889 | 890 | Tcl_IncrRefCount(objPtr); 891 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr); 892 | Tcl_DecrRefCount(objPtr); 893 | 894 | if (code != TCL_OK) 895 | goto done; 896 | } 897 | 898 | Tcl_SetObjResult(interp, listPtr); 899 | 900 | done: 901 | if (listPtr != NULL) { 902 | Tcl_DecrRefCount(listPtr); 903 | listPtr = NULL; 904 | } 905 | 906 | return code; 907 | } 908 | 909 | /* 910 | *---------------------------------------------------------------------- 911 | * 912 | * CompileForType -- 913 | * 914 | * This function attempts to create a Sass_Context based on the 915 | * specified Sass_Context_Type, compile it, and then set the Tcl 916 | * interpreter result based on its output. A script error will 917 | * be generated if the context type is unsupported -OR- context 918 | * creation fails -OR- context compilation fails. 919 | * 920 | * Results: 921 | * A standard Tcl result. 922 | * 923 | * Side effects: 924 | * None. 925 | * 926 | *---------------------------------------------------------------------- 927 | */ 928 | 929 | static int CompileForType( 930 | Tcl_Interp *interp, 931 | enum Sass_Context_Type type, 932 | struct Sass_Options **pOptsPtr, 933 | const char* zSource) 934 | { 935 | if (interp == NULL) { 936 | PACKAGE_TRACE(("CompileForType: no Tcl interpreter\n")); 937 | return TCL_ERROR; 938 | } 939 | 940 | if (pOptsPtr == NULL) { 941 | Tcl_AppendResult(interp, "no options pointer\n", NULL); 942 | return TCL_ERROR; 943 | } 944 | 945 | if (zSource == NULL) { 946 | Tcl_AppendResult(interp, "no source\n", NULL); 947 | return TCL_ERROR; 948 | } 949 | 950 | switch (type) { 951 | case SASS_CONTEXT_FILE: { 952 | struct Sass_File_Context *ctxPtr; 953 | 954 | ctxPtr = sass_make_file_context(zSource); 955 | 956 | if (ctxPtr == NULL) { 957 | Tcl_AppendResult(interp, "out of memory: ctxPtr\n", NULL); 958 | return TCL_ERROR; 959 | } 960 | 961 | if (*pOptsPtr != NULL) { 962 | sass_file_context_set_options(ctxPtr, *pOptsPtr); 963 | *pOptsPtr = NULL; 964 | } 965 | 966 | sass_compile_file_context(ctxPtr); 967 | SetResultFromContext(interp, (struct Sass_Context *)ctxPtr); 968 | sass_delete_file_context(ctxPtr); 969 | 970 | return TCL_OK; 971 | } 972 | case SASS_CONTEXT_DATA: { 973 | struct Sass_Data_Context *ctxPtr; 974 | char *zDup = strdup(zSource); 975 | 976 | if (zDup == NULL) { 977 | Tcl_AppendResult(interp, "out of memory: zDup\n", NULL); 978 | return TCL_ERROR; 979 | } 980 | 981 | ctxPtr = sass_make_data_context(zDup); 982 | 983 | if (ctxPtr == NULL) { 984 | free(zDup); 985 | Tcl_AppendResult(interp, "out of memory: ctxPtr\n", NULL); 986 | return TCL_ERROR; 987 | } 988 | 989 | if (*pOptsPtr != NULL) { 990 | sass_data_context_set_options(ctxPtr, *pOptsPtr); 991 | *pOptsPtr = NULL; 992 | } 993 | 994 | sass_compile_data_context(ctxPtr); 995 | SetResultFromContext(interp, (struct Sass_Context *)ctxPtr); 996 | sass_delete_data_context(ctxPtr); 997 | #ifdef TCLSASS_CALLER_FREE 998 | free(zDup); 999 | #endif 1000 | 1001 | return TCL_OK; 1002 | } 1003 | default: { 1004 | char buffer[50] = {0}; 1005 | 1006 | snprintf(buffer, sizeof(buffer) - 1, 1007 | "cannot compile, unsupported type %d\n", type); 1008 | 1009 | Tcl_AppendResult(interp, buffer, NULL); 1010 | return TCL_ERROR; 1011 | } 1012 | } 1013 | } 1014 | 1015 | /* 1016 | *---------------------------------------------------------------------- 1017 | * 1018 | * Sass_Init -- 1019 | * 1020 | * This function initializes the package for the specified Tcl 1021 | * interpreter. 1022 | * 1023 | * Results: 1024 | * A standard Tcl result. 1025 | * 1026 | * Side effects: 1027 | * None. 1028 | * 1029 | *---------------------------------------------------------------------- 1030 | */ 1031 | 1032 | int Sass_Init( 1033 | Tcl_Interp *interp) /* Current Tcl interpreter. */ 1034 | { 1035 | int code = TCL_OK; 1036 | Tcl_Command command; 1037 | 1038 | /* 1039 | * NOTE: Make sure the Tcl interpreter is valid and then try to initialize 1040 | * the Tcl stubs table. We cannot call any Tcl API unless this call 1041 | * succeeds. 1042 | */ 1043 | 1044 | if ((interp == NULL) || !Tcl_InitStubs(interp, PACKAGE_TCL_VERSION, 0)) { 1045 | PACKAGE_TRACE(("Sass_Init: Tcl stubs were not initialized\n")); 1046 | return TCL_ERROR; 1047 | } 1048 | 1049 | /* 1050 | * NOTE: Add our exit handler prior to performing any actions that need to 1051 | * be undone by it. However, first delete it in case it has already 1052 | * been added. If it has never been added, trying to delete it will 1053 | * be a harmless no-op. This appears to be necessary to ensure that 1054 | * our exit handler has been added exactly once after this point. 1055 | */ 1056 | 1057 | Tcl_DeleteExitHandler(SassExitProc, NULL); 1058 | Tcl_CreateExitHandler(SassExitProc, NULL); 1059 | 1060 | /* 1061 | * NOTE: Create our command in the Tcl interpreter. 1062 | */ 1063 | 1064 | command = Tcl_CreateObjCommand(interp, COMMAND_NAME, SassObjCmd, interp, 1065 | SassObjCmdDeleteProc); 1066 | 1067 | if (command == NULL) { 1068 | Tcl_AppendResult(interp, "command creation failed\n", NULL); 1069 | code = TCL_ERROR; 1070 | goto done; 1071 | } 1072 | 1073 | /* 1074 | * NOTE: Store the token for the command created by this package. This 1075 | * way, we can properly delete it when the package is being unloaded. 1076 | */ 1077 | 1078 | Tcl_SetAssocData(interp, PACKAGE_NAME, NULL, command); 1079 | 1080 | /* 1081 | * NOTE: Finally, attempt to provide this package in the Tcl interpreter. 1082 | */ 1083 | 1084 | code = Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_VERSION); 1085 | 1086 | done: 1087 | /* 1088 | * NOTE: If some step of loading the package failed, attempt to cleanup now 1089 | * by unloading the package, either from just this Tcl interpreter or 1090 | * from the entire process. 1091 | */ 1092 | 1093 | if (code != TCL_OK) { 1094 | if (Sass_Unload(interp, TCL_UNLOAD_FROM_INIT) != TCL_OK) { 1095 | /* 1096 | * NOTE: We failed to undo something and we have no nice way of 1097 | * reporting this failure; therefore, complain about it. 1098 | */ 1099 | 1100 | PACKAGE_PANIC(("Sass_Unload: failed via Sass_Init\n")); 1101 | } 1102 | } 1103 | 1104 | return code; 1105 | } 1106 | 1107 | /* 1108 | *---------------------------------------------------------------------- 1109 | * 1110 | * Sass_SafeInit -- 1111 | * 1112 | * This function initializes the package for the specified safe 1113 | * Tcl interpreter. 1114 | * 1115 | * Results: 1116 | * A standard Tcl result. 1117 | * 1118 | * Side effects: 1119 | * None. 1120 | * 1121 | *---------------------------------------------------------------------- 1122 | */ 1123 | 1124 | int Sass_SafeInit( 1125 | Tcl_Interp *interp) /* Current Tcl interpreter. */ 1126 | { 1127 | return Sass_Init(interp); 1128 | } 1129 | 1130 | /* 1131 | *---------------------------------------------------------------------- 1132 | * 1133 | * Sass_Unload -- 1134 | * 1135 | * This function unloads the package from the specified Tcl 1136 | * interpreter -OR- from the entire process. 1137 | * 1138 | * Results: 1139 | * A standard Tcl result. 1140 | * 1141 | * Side effects: 1142 | * None. 1143 | * 1144 | *---------------------------------------------------------------------- 1145 | */ 1146 | 1147 | int Sass_Unload( 1148 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 1149 | int flags) /* Unload behavior flags. */ 1150 | { 1151 | int code = TCL_OK; 1152 | int bShutdown = (flags & TCL_UNLOAD_DETACH_FROM_PROCESS); 1153 | 1154 | /* 1155 | * NOTE: If we have a valid Tcl interpreter, try to get the token for the 1156 | * command added to it when the package was being loaded. We need to 1157 | * delete the command now because the whole library may be unloading. 1158 | */ 1159 | 1160 | if (interp != NULL) { 1161 | Tcl_Command command = Tcl_GetAssocData(interp, PACKAGE_NAME, NULL); 1162 | 1163 | if (command != NULL) { 1164 | if (Tcl_DeleteCommandFromToken(interp, command) != 0) { 1165 | Tcl_AppendResult(interp, "command deletion failed\n", NULL); 1166 | code = TCL_ERROR; 1167 | goto done; 1168 | } 1169 | } 1170 | 1171 | /* 1172 | * NOTE: Always delete our saved association data from the Tcl 1173 | * interpreter because the Tcl_GetAssocData function does not 1174 | * reserve any return value to indicate "failure" or "not found" 1175 | * and calling the Tcl_DeleteAssocData function for association 1176 | * data that does not exist is a harmless no-op. 1177 | */ 1178 | 1179 | Tcl_DeleteAssocData(interp, PACKAGE_NAME); 1180 | } 1181 | 1182 | /* 1183 | * NOTE: Delete our exit handler after performing the actions that needed 1184 | * to be undone. However, this should only be done if the package 1185 | * is actually being unloaded from the process; otherwise, none of 1186 | * the process-wide cleanup was done and it must be done later. If 1187 | * this function is actually being called from our exit handler now, 1188 | * trying to delete our exit handler will be a harmless no-op. 1189 | */ 1190 | 1191 | if (bShutdown) 1192 | Tcl_DeleteExitHandler(SassExitProc, NULL); 1193 | 1194 | done: 1195 | /* 1196 | * NOTE: If possible, log this attempt to unload the package, including 1197 | * the saved package module handle, the associated module file name, 1198 | * the current Tcl interpreter, the flags, and the return code. 1199 | */ 1200 | 1201 | PACKAGE_TRACE(("Sass_Unload(interp = {" 1202 | PACKAGE_PTR_FMT "}, flags = {" PACKAGE_HEX_FMT "}, code = {%d})\n", 1203 | interp, flags, code)); 1204 | 1205 | return code; 1206 | } 1207 | 1208 | /* 1209 | *---------------------------------------------------------------------- 1210 | * 1211 | * Sass_SafeUnload -- 1212 | * 1213 | * This function unloads the package from the specified safe Tcl 1214 | * interpreter -OR- from the entire process. 1215 | * 1216 | * Results: 1217 | * A standard Tcl result. 1218 | * 1219 | * Side effects: 1220 | * None. 1221 | * 1222 | *---------------------------------------------------------------------- 1223 | */ 1224 | 1225 | int Sass_SafeUnload( 1226 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 1227 | int flags) /* Unload behavior flags. */ 1228 | { 1229 | return Sass_Unload(interp, flags); 1230 | } 1231 | 1232 | /* 1233 | *---------------------------------------------------------------------- 1234 | * 1235 | * SassExitProc -- 1236 | * 1237 | * Cleanup all the resources allocated by this package. 1238 | * 1239 | * Results: 1240 | * None. 1241 | * 1242 | * Side effects: 1243 | * None. 1244 | * 1245 | *---------------------------------------------------------------------- 1246 | */ 1247 | 1248 | static void SassExitProc( 1249 | ClientData clientData) /* Not used. */ 1250 | { 1251 | if (Sass_Unload(NULL, 1252 | TCL_UNLOAD_DETACH_FROM_PROCESS) != TCL_OK) 1253 | { 1254 | /* 1255 | * NOTE: We failed to undo something and we have no nice way of 1256 | * reporting this failure; therefore, complain about it. 1257 | */ 1258 | 1259 | PACKAGE_PANIC(("Sass_Unload: failed via SassExitProc\n")); 1260 | } 1261 | } 1262 | 1263 | /* 1264 | *---------------------------------------------------------------------- 1265 | * 1266 | * SassObjCmd -- 1267 | * 1268 | * Handles the command(s) added by this package. This command is 1269 | * aware of safe Tcl interpreters. For safe Tcl interpreters, all 1270 | * sub-commands are allowed. 1271 | * 1272 | * Results: 1273 | * A standard Tcl result. 1274 | * 1275 | * Side effects: 1276 | * One or more libsass library functions may be called, resulting 1277 | * in whatever effects they may have. 1278 | * 1279 | *---------------------------------------------------------------------- 1280 | */ 1281 | 1282 | static int SassObjCmd( 1283 | ClientData clientData, /* Not used. */ 1284 | Tcl_Interp *interp, /* Current Tcl interpreter. */ 1285 | int objc, /* Number of arguments. */ 1286 | Tcl_Obj *CONST objv[]) /* The array of arguments. */ 1287 | { 1288 | int code = TCL_OK; 1289 | int option; 1290 | enum Sass_Context_Type type = SASS_CONTEXT_NULL; 1291 | struct Sass_Options *optsPtr = NULL; 1292 | 1293 | static const char *cmdOptions[] = { 1294 | "compile", "version", (char *) NULL 1295 | }; 1296 | 1297 | enum options { 1298 | OPT_COMPILE, OPT_VERSION 1299 | }; 1300 | 1301 | if (interp == NULL) { 1302 | PACKAGE_TRACE(("SassObjCmd: no Tcl interpreter\n")); 1303 | return TCL_ERROR; 1304 | } 1305 | 1306 | if (objc < 2) { 1307 | Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); 1308 | return TCL_ERROR; 1309 | } 1310 | 1311 | if (Tcl_GetIndexFromObj(interp, objv[1], cmdOptions, "option", 0, 1312 | &option) != TCL_OK) { 1313 | return TCL_ERROR; 1314 | } 1315 | 1316 | switch ((enum options)option) { 1317 | case OPT_COMPILE: { 1318 | int index = 2; /* NOTE: Start right after "sass compile". */ 1319 | 1320 | if (objc < 3) { 1321 | Tcl_WrongNumArgs(interp, 2, objv, "?options? source"); 1322 | return TCL_ERROR; 1323 | } 1324 | 1325 | optsPtr = sass_make_options(); 1326 | 1327 | if (optsPtr == NULL) { 1328 | Tcl_AppendResult(interp, "out of memory: optsPtr\n", NULL); 1329 | code = TCL_ERROR; 1330 | goto done; 1331 | } 1332 | 1333 | code = ProcessContextOptions(interp, objc, objv, &index, &type, 1334 | optsPtr); 1335 | 1336 | if (code != TCL_OK) 1337 | goto done; 1338 | 1339 | if ((index < 0) || ((index + 1) != objc)) { 1340 | Tcl_WrongNumArgs(interp, 2, objv, "?options? source"); 1341 | code = TCL_ERROR; 1342 | goto done; 1343 | } 1344 | 1345 | code = CompileForType(interp, type, &optsPtr, 1346 | Tcl_GetString(objv[index])); 1347 | 1348 | break; 1349 | } 1350 | case OPT_VERSION: { 1351 | Tcl_Obj *listPtr; 1352 | Tcl_Obj *objPtr1; 1353 | Tcl_Obj *objPtr2; 1354 | 1355 | if (objc != 2) { 1356 | Tcl_WrongNumArgs(interp, 2, objv, NULL); 1357 | return TCL_ERROR; 1358 | } 1359 | 1360 | listPtr = Tcl_NewListObj(0, NULL); 1361 | 1362 | if (listPtr == NULL) { 1363 | Tcl_AppendResult(interp, "out of memory: listPtr\n", NULL); 1364 | code = TCL_ERROR; 1365 | goto done; 1366 | } 1367 | 1368 | Tcl_IncrRefCount(listPtr); 1369 | objPtr1 = Tcl_NewStringObj("libsass", -1); 1370 | 1371 | if (objPtr1 == NULL) { 1372 | Tcl_DecrRefCount(listPtr); 1373 | Tcl_AppendResult(interp, "out of memory: objPtr1\n", NULL); 1374 | code = TCL_ERROR; 1375 | goto done; 1376 | } 1377 | 1378 | Tcl_IncrRefCount(objPtr1); 1379 | objPtr2 = Tcl_NewStringObj(libsass_version(), -1); 1380 | 1381 | if (objPtr2 == NULL) { 1382 | Tcl_DecrRefCount(objPtr1); 1383 | Tcl_DecrRefCount(listPtr); 1384 | Tcl_AppendResult(interp, "out of memory: objPtr2\n", NULL); 1385 | code = TCL_ERROR; 1386 | goto done; 1387 | } 1388 | 1389 | Tcl_IncrRefCount(objPtr2); 1390 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr1); 1391 | 1392 | if (code != TCL_OK) { 1393 | Tcl_DecrRefCount(objPtr2); 1394 | Tcl_DecrRefCount(objPtr1); 1395 | Tcl_DecrRefCount(listPtr); 1396 | code = TCL_ERROR; 1397 | goto done; 1398 | } 1399 | 1400 | code = Tcl_ListObjAppendElement(interp, listPtr, objPtr2); 1401 | 1402 | if (code != TCL_OK) { 1403 | Tcl_DecrRefCount(objPtr2); 1404 | Tcl_DecrRefCount(objPtr1); 1405 | Tcl_DecrRefCount(listPtr); 1406 | code = TCL_ERROR; 1407 | goto done; 1408 | } 1409 | 1410 | Tcl_SetObjResult(interp, listPtr); 1411 | Tcl_DecrRefCount(objPtr2); 1412 | Tcl_DecrRefCount(objPtr1); 1413 | Tcl_DecrRefCount(listPtr); 1414 | break; 1415 | } 1416 | default: { 1417 | Tcl_AppendResult(interp, "bad option index\n", NULL); 1418 | code = TCL_ERROR; 1419 | goto done; 1420 | } 1421 | } 1422 | 1423 | done: 1424 | if (optsPtr != NULL) { 1425 | #ifdef HAVE_SASS_DELETE_OPTIONS 1426 | /* libsass 3.5.x adds the delete function to match the make function. */ 1427 | sass_delete_options(optsPtr); 1428 | #else 1429 | free(optsPtr); 1430 | #endif 1431 | optsPtr = NULL; 1432 | } 1433 | 1434 | return code; 1435 | } 1436 | 1437 | /* 1438 | *---------------------------------------------------------------------- 1439 | * 1440 | * SassObjCmdDeleteProc -- 1441 | * 1442 | * Handles deletion of the command(s) added by this package. 1443 | * This will cause the saved package data associated with the 1444 | * Tcl interpreter to be deleted, if it has not been already. 1445 | * 1446 | * Results: 1447 | * None. 1448 | * 1449 | * Side effects: 1450 | * None. 1451 | * 1452 | *---------------------------------------------------------------------- 1453 | */ 1454 | 1455 | static void SassObjCmdDeleteProc( 1456 | ClientData clientData) /* Current Tcl interpreter. */ 1457 | { 1458 | /* 1459 | * NOTE: The client data for this callback function should be the 1460 | * pointer to the Tcl interpreter. It must be valid. 1461 | */ 1462 | 1463 | Tcl_Interp *interp = (Tcl_Interp *) clientData; 1464 | 1465 | if (interp == NULL) { 1466 | PACKAGE_TRACE(("SassObjCmdDeleteProc: no Tcl interpreter\n")); 1467 | return; 1468 | } 1469 | 1470 | /* 1471 | * NOTE: Delete our saved association data from the Tcl interpreter 1472 | * because it only serves to help us delete the Tcl command 1473 | * that is apparently already in the process of being deleted. 1474 | */ 1475 | 1476 | Tcl_DeleteAssocData(interp, PACKAGE_NAME); 1477 | } 1478 | --------------------------------------------------------------------------------