protected static function parseArgs($input, $allowSpaceDelim = false)
 {
     $args = csscrush_util::splitDelimList($input, $allowSpaceDelim ? '\\s*[,\\s]\\s*' : ',', true, true);
     return array_map('trim', $args->list);
 }
    protected static function rewriteImportRelativeUrls($import)
    {
        $stream = $import->content;
        // We're comparing file system position so we'll
        $hostDir = csscrush_util::normalizeSystemPath($import->hostDir, true);
        $importDir = csscrush_util::normalizeSystemPath(dirname($import->path), true);
        csscrush::$storage->tmp->relativeUrlPrefix = '';
        $url_prefix = '';
        if ($importDir === $hostDir) {
            // Do nothing if files are in the same directory
            return $stream;
        } elseif (strpos($importDir, $hostDir) === false) {
            // Import directory is higher than the host directory
            // Split the directory paths into arrays so we can compare segment by segment
            $host_segs = preg_split('!/+!', $hostDir, null, PREG_SPLIT_NO_EMPTY);
            $import_segs = preg_split('!/+!', $importDir, null, PREG_SPLIT_NO_EMPTY);
            // Shift the segments until they are on different branches
            while (@($host_segs[0] == $import_segs[0])) {
                array_shift($host_segs);
                array_shift($import_segs);
                // csscrush::log( array( $host_segs, $import_segs ) );
            }
            // Count the remaining $host_segs to get the offset
            $level_diff = count($host_segs);
            $url_prefix = str_repeat('../', $level_diff) . implode('/', $import_segs);
        } else {
            // Import directory is lower than host directory
            // easy, url_prefix is the difference
            $url_prefix = substr($importDir, strlen($hostDir) + 1);
        }
        if (empty($url_prefix)) {
            return $stream;
        }
        // Add the directory seperator ending (if needed)
        if ($url_prefix[strlen($url_prefix) - 1] !== '/') {
            $url_prefix .= '/';
        }
        csscrush::log('relative_url_prefix: ' . $url_prefix);
        // Search for all relative url and data-uri references in the content
        // and prepend $relative_url_prefix
        // Make $url_prefix accessible in callback scope
        csscrush::$storage->tmp->relativeUrlPrefix = $url_prefix;
        $url_function_patt = '!
			([^a-z-])         # the preceeding character
			(data-uri|url)    # the function name
			\\(\\s*([^\\)]+)\\s*\\) # the url
		!xi';
        $stream = preg_replace_callback($url_function_patt, array('self', 'cb_rewriteImportRelativeUrl'), $stream);
        return $stream;
    }
 protected static function cb_extractVariables($match)
 {
     $regex = self::$regex;
     $block = $match[2];
     // Strip comment markers
     $block = preg_replace($regex->token->comment, '', $block);
     // Need to split safely as there are semi-colons in data-uris
     $variables_match = csscrush_util::splitDelimList($block, ';', true);
     // Loop through the pairs, restore parens
     foreach ($variables_match->list as $var) {
         $colon = strpos($var, ':');
         if ($colon === -1) {
             continue;
         }
         $name = trim(substr($var, 0, $colon));
         $value = trim(substr($var, $colon + 1));
         self::$storage->variables[trim($name)] = $value;
     }
     return '';
 }
 public function __construct($selector_string = null, $declarations_string)
 {
     $regex = csscrush::$regex;
     // Parse the selectors chunk
     if (!empty($selector_string)) {
         $selectors_match = csscrush_util::splitDelimList($selector_string, ',');
         $this->parens += $selectors_match->matches;
         // Remove and store comments that sit above the first selector
         // remove all comments between the other selectors
         preg_match_all($regex->token->comment, $selectors_match->list[0], $m);
         $this->comments = $m[0];
         foreach ($selectors_match->list as &$selector) {
             $selector = preg_replace($regex->token->comment, '', $selector);
             $selector = trim($selector);
         }
         $this->selectors = $selectors_match->list;
     }
     // Apply any custom functions
     $declarations_string = csscrush_function::parseAndExecuteValue($declarations_string);
     // Parse the declarations chunk
     // Need to split safely as there are semi-colons in data-uris
     $declarations_match = csscrush_util::splitDelimList($declarations_string, ';');
     $this->parens += $declarations_match->matches;
     // Parse declarations in to property/value pairs
     foreach ($declarations_match->list as $declaration) {
         // Strip comments around the property
         $declaration = preg_replace($regex->token->comment, '', $declaration);
         // Store the property
         $colonPos = strpos($declaration, ':');
         if ($colonPos === false) {
             // If there is no colon it's malformed
             continue;
         }
         // The property name
         $prop = trim(substr($declaration, 0, $colonPos));
         // Test for escape tilde
         if ($skip = strpos($prop, '~') === 0) {
             $prop = substr($prop, 1);
         }
         // Store the property name
         $this->addProperty($prop);
         // Store the property family
         // Store the vendor id, if one is present
         if (preg_match($regex->vendorPrefix, $prop, $vendor)) {
             $family = $vendor[2];
             $vendor = $vendor[1];
         } else {
             $vendor = null;
             $family = $prop;
         }
         // Extract the value part of the declaration
         $value = substr($declaration, $colonPos + 1);
         $value = $value !== false ? trim($value) : $value;
         if ($value === false or $value === '') {
             // We'll ignore declarations with empty values
             continue;
         }
         // Create an index of all functions in the current declaration
         if (preg_match_all($regex->function->match, $value, $functions) > 0) {
             // csscrush::log( $functions );
             $out = array();
             foreach ($functions[2] as $index => $fn_name) {
                 $out[] = $fn_name;
             }
             $functions = array_unique($out);
         } else {
             $functions = array();
         }
         // Store the declaration
         $_declaration = (object) array('property' => $prop, 'family' => $family, 'vendor' => $vendor, 'functions' => $functions, 'value' => $value, 'skip' => $skip);
         $this->declarations[] = $_declaration;
     }
 }