From 8fcc303b842d94eccfc05fdf6cfd0b78d9123006 Mon Sep 17 00:00:00 2001 From: Ludovic CHEVALIER Date: Thu, 20 Mar 2014 18:34:03 +0100 Subject: [PATCH] [PLUGINS] +yaml --- scripts/menu-barrenav.yaml | 19 + www/plugins/skel_ptitvelo/paquet.xml | 1 + www/plugins/yaml/demo/iter_data_yaml.html | 17 + www/plugins/yaml/experimental/README | 9 + www/plugins/yaml/experimental/yaml.html | 5 + .../yaml/experimental/yaml_fonctions.php | 16 + www/plugins/yaml/inc/yaml.php | 110 ++ www/plugins/yaml/inc/yaml_sfyaml.php | 36 + www/plugins/yaml/inc/yaml_to_array.php | 15 + www/plugins/yaml/lang/paquet-yaml.xml | 20 + www/plugins/yaml/lang/paquet-yaml_en.php | 16 + www/plugins/yaml/lang/paquet-yaml_es.php | 15 + www/plugins/yaml/lang/paquet-yaml_fa.php | 15 + www/plugins/yaml/lang/paquet-yaml_fr.php | 14 + www/plugins/yaml/lang/paquet-yaml_ru.php | 16 + www/plugins/yaml/lang/paquet-yaml_sk.php | 16 + www/plugins/yaml/paquet.xml | 19 + www/plugins/yaml/plugin.xml | 19 + www/plugins/yaml/sfyaml/sfYaml.php | 145 +++ www/plugins/yaml/sfyaml/sfYamlDumper.php | 60 + www/plugins/yaml/sfyaml/sfYamlInline.php | 424 +++++++ www/plugins/yaml/sfyaml/sfYamlParser.php | 540 +++++++++ www/plugins/yaml/spyc/spyc-php4.php | 1024 ++++++++++++++++ www/plugins/yaml/spyc/spyc.php | 1046 +++++++++++++++++ www/plugins/yaml/svn.revision | 10 + www/plugins/yaml/yaml.png | Bin 0 -> 12232 bytes www/plugins/yaml/yaml_fonctions.php | 17 + 27 files changed, 3644 insertions(+) create mode 100644 scripts/menu-barrenav.yaml create mode 100644 www/plugins/yaml/demo/iter_data_yaml.html create mode 100644 www/plugins/yaml/experimental/README create mode 100644 www/plugins/yaml/experimental/yaml.html create mode 100644 www/plugins/yaml/experimental/yaml_fonctions.php create mode 100644 www/plugins/yaml/inc/yaml.php create mode 100644 www/plugins/yaml/inc/yaml_sfyaml.php create mode 100644 www/plugins/yaml/inc/yaml_to_array.php create mode 100644 www/plugins/yaml/lang/paquet-yaml.xml create mode 100644 www/plugins/yaml/lang/paquet-yaml_en.php create mode 100644 www/plugins/yaml/lang/paquet-yaml_es.php create mode 100644 www/plugins/yaml/lang/paquet-yaml_fa.php create mode 100644 www/plugins/yaml/lang/paquet-yaml_fr.php create mode 100644 www/plugins/yaml/lang/paquet-yaml_ru.php create mode 100644 www/plugins/yaml/lang/paquet-yaml_sk.php create mode 100644 www/plugins/yaml/paquet.xml create mode 100644 www/plugins/yaml/plugin.xml create mode 100755 www/plugins/yaml/sfyaml/sfYaml.php create mode 100755 www/plugins/yaml/sfyaml/sfYamlDumper.php create mode 100755 www/plugins/yaml/sfyaml/sfYamlInline.php create mode 100755 www/plugins/yaml/sfyaml/sfYamlParser.php create mode 100644 www/plugins/yaml/spyc/spyc-php4.php create mode 100644 www/plugins/yaml/spyc/spyc.php create mode 100644 www/plugins/yaml/svn.revision create mode 100644 www/plugins/yaml/yaml.png create mode 100644 www/plugins/yaml/yaml_fonctions.php diff --git a/scripts/menu-barrenav.yaml b/scripts/menu-barrenav.yaml new file mode 100644 index 0000000..c6e957e --- /dev/null +++ b/scripts/menu-barrenav.yaml @@ -0,0 +1,19 @@ +- + type_entree: texte_libre + parametres: { contenu: 'L''association', css: '' } + sous_menu: [{ type_entree: objet, parametres: { type_objet: article, id_objet: '31', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '75', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '77', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '76', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '70', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '5', titre: '', css: '', connexion: '', trad: '' } }] +- + type_entree: texte_libre + parametres: { contenu: 'Les activités', css: '' } + sous_menu: [{ type_entree: objet, parametres: { type_objet: rubrique, id_objet: '73', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '83', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '80', titre: '', css: '', connexion: '', trad: '' } }] +- + type_entree: texte_libre + parametres: { contenu: Rejoignez-nous, css: '' } + sous_menu: [{ type_entree: objet, parametres: { type_objet: rubrique, id_objet: '66', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '67', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '82', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '65', titre: '', css: '', connexion: '', trad: '' } }] +- + type_entree: texte_libre + parametres: { contenu: Réseaux, css: '' } + sous_menu: [{ type_entree: objet, parametres: { type_objet: rubrique, id_objet: '68', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '71', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '81', titre: '', css: '', connexion: '', trad: '' } }, { type_entree: objet, parametres: { type_objet: rubrique, id_objet: '69', titre: '', css: '', connexion: '', trad: '' } }] +- + type_entree: objet + parametres: { type_objet: rubrique, id_objet: '78', titre: '', css: '', connexion: '', trad: '' } diff --git a/www/plugins/skel_ptitvelo/paquet.xml b/www/plugins/skel_ptitvelo/paquet.xml index a6acf9c..6276b8b 100644 --- a/www/plugins/skel_ptitvelo/paquet.xml +++ b/www/plugins/skel_ptitvelo/paquet.xml @@ -20,4 +20,5 @@ + diff --git a/www/plugins/yaml/demo/iter_data_yaml.html b/www/plugins/yaml/demo/iter_data_yaml.html new file mode 100644 index 0000000..9b52dce --- /dev/null +++ b/www/plugins/yaml/demo/iter_data_yaml.html @@ -0,0 +1,17 @@ +#CACHE{0} + +

(DATA) YAML

+ +
+ + +#PAGINATION +
#TOTAL_BOUCLE/#GRAND_TOTAL + +
#CLE
+
[(#VALEUR|print)]
+ + +
diff --git a/www/plugins/yaml/experimental/README b/www/plugins/yaml/experimental/README new file mode 100644 index 0000000..e7e8012 --- /dev/null +++ b/www/plugins/yaml/experimental/README @@ -0,0 +1,9 @@ +Installer ces deux fichiers dans les squelettes + +Puis appeler spip.php?page=yaml&id_article=X + +ou alors dans .htaccess ajouter : +RewriteRule ^article([0-9]+)[\.,]yaml$ spip.php?page=yaml&id_article=$1 [QSA,L] + +puis appeler articleXXX,yaml + diff --git a/www/plugins/yaml/experimental/yaml.html b/www/plugins/yaml/experimental/yaml.html new file mode 100644 index 0000000..38f5ce7 --- /dev/null +++ b/www/plugins/yaml/experimental/yaml.html @@ -0,0 +1,5 @@ +#HTTP_HEADER{Content-Type: text/plain; charset=#CHARSET} + +# Article #ID_ARTICLE du site #URL_SITE_SPIP* +[(#ID_ARTICLE|yaml_article)] + diff --git a/www/plugins/yaml/experimental/yaml_fonctions.php b/www/plugins/yaml/experimental/yaml_fonctions.php new file mode 100644 index 0000000..a9f27e5 --- /dev/null +++ b/www/plugins/yaml/experimental/yaml_fonctions.php @@ -0,0 +1,16 @@ + $valeur) { + if (is_string($valeur) && substr($valeur,0,8)=='inclure:' && substr($valeur,-5)=='.yaml') + $retour = array_merge($retour,yaml_charger_inclusions(yaml_decode_file(find_in_path(substr($valeur,8))))); + elseif (is_array($valeur)) + $retour = array_merge($retour,array($cle => yaml_charger_inclusions($valeur))); + else + $retour = array_merge($retour,array($cle => $valeur)); + } + return $retour; + } + elseif (is_string($tableau) && substr($tableau,0,8)=='inclure:' && substr($tableau,-5)=='.yaml') + return yaml_charger_inclusions(yaml_decode_file(find_in_path(substr($tableau,8)))); + else + return $tableau; +} + +?> diff --git a/www/plugins/yaml/inc/yaml_sfyaml.php b/www/plugins/yaml/inc/yaml_sfyaml.php new file mode 100644 index 0000000..1d94844 --- /dev/null +++ b/www/plugins/yaml/inc/yaml_sfyaml.php @@ -0,0 +1,36 @@ + 2 + ), $opt); + $yaml = new sfYamlDumper(); + return $yaml->dump($struct, $opt['inline']); +} + +function yaml_sfyaml_decode($input,$show_error=true) { + require_once _DIR_PLUGIN_YAML.'sfyaml/sfYaml.php'; + require_once _DIR_PLUGIN_YAML.'sfyaml/sfYamlParser.php'; + + $yaml = new sfYamlParser(); + + try + { + $ret = $yaml->parse($input); + } + catch (Exception $e) + { + if ($show_error) + throw new InvalidArgumentException(sprintf('Unable to parse string: %s', $e->getMessage())); + else + return false; + } + + return $ret; +} + +?> \ No newline at end of file diff --git a/www/plugins/yaml/inc/yaml_to_array.php b/www/plugins/yaml/inc/yaml_to_array.php new file mode 100644 index 0000000..75969ef --- /dev/null +++ b/www/plugins/yaml/inc/yaml_to_array.php @@ -0,0 +1,15 @@ + diff --git a/www/plugins/yaml/lang/paquet-yaml.xml b/www/plugins/yaml/lang/paquet-yaml.xml new file mode 100644 index 0000000..1f1c505 --- /dev/null +++ b/www/plugins/yaml/lang/paquet-yaml.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/www/plugins/yaml/lang/paquet-yaml_en.php b/www/plugins/yaml/lang/paquet-yaml_en.php new file mode 100644 index 0000000..7bae352 --- /dev/null +++ b/www/plugins/yaml/lang/paquet-yaml_en.php @@ -0,0 +1,16 @@ + 'This plugin provides the functions for reading/writing YAML format: +yaml_decode() and yaml_encode(). It also provides the yaml format for the (DATA) loop.', + 'yaml_slogan' => 'A simple file format for editing lists of data' +); + +?> diff --git a/www/plugins/yaml/lang/paquet-yaml_es.php b/www/plugins/yaml/lang/paquet-yaml_es.php new file mode 100644 index 0000000..90af6eb --- /dev/null +++ b/www/plugins/yaml/lang/paquet-yaml_es.php @@ -0,0 +1,15 @@ + 'Este plugin proporciona las funciones de lectura/escritura del formato YAML: yaml_decode() y yaml_encode(). También proporciona el formato yaml para el bucle (DATA).', + 'yaml_slogan' => 'Un formato de archivo simple para editar listas de datos' +); + +?> diff --git a/www/plugins/yaml/lang/paquet-yaml_fa.php b/www/plugins/yaml/lang/paquet-yaml_fa.php new file mode 100644 index 0000000..9d298e7 --- /dev/null +++ b/www/plugins/yaml/lang/paquet-yaml_fa.php @@ -0,0 +1,15 @@ + 'اين پلاگين كاركردهاي خواندن/نوشتن فرمت يا.اي.ام.ال را فراهم مي‌آورد: yaml_decode() وyaml_encode(). همچنين فرمت يا.اي.ام.ال را براي حلقه‌ي (DATA) فراهم مي‌سازد.', + 'yaml_slogan' => 'فرمتي براي پروند‌ه ساده براي ويرايش فهرست‌هاي داده‌ها' +); + +?> diff --git a/www/plugins/yaml/lang/paquet-yaml_fr.php b/www/plugins/yaml/lang/paquet-yaml_fr.php new file mode 100644 index 0000000..9933ac5 --- /dev/null +++ b/www/plugins/yaml/lang/paquet-yaml_fr.php @@ -0,0 +1,14 @@ + 'Ce plugin fournit les fonctions de lecture/écriture du format YAML : + yaml_decode() et yaml_encode(). Il fournit aussi le format yaml pour la boucle (DATA).', + 'yaml_slogan' => 'Un format de fichier simple pour éditer des listes de données' +); + +?> diff --git a/www/plugins/yaml/lang/paquet-yaml_ru.php b/www/plugins/yaml/lang/paquet-yaml_ru.php new file mode 100644 index 0000000..8691623 --- /dev/null +++ b/www/plugins/yaml/lang/paquet-yaml_ru.php @@ -0,0 +1,16 @@ + 'Плагин позволяет использовать функции чтения/записи в формате YAML: + yaml_decode() и yaml_encode(). И позволяет использовать YAML в запросе BOUCLE(DATA).', + 'yaml_slogan' => 'Позволяет работать с YAML форматом' +); + +?> diff --git a/www/plugins/yaml/lang/paquet-yaml_sk.php b/www/plugins/yaml/lang/paquet-yaml_sk.php new file mode 100644 index 0000000..4b44dfb --- /dev/null +++ b/www/plugins/yaml/lang/paquet-yaml_sk.php @@ -0,0 +1,16 @@ + 'Tento zásuvný modul ponúka funkcie čítanie/zápisu formátu YAML: + yaml_decode() a yaml_encode(). Poskytuje formát yaml aj pre cyklus (DATA).', + 'yaml_slogan' => 'Jednoduchý formát súborov na upravovanie zoznamov dát' +); + +?> diff --git a/www/plugins/yaml/paquet.xml b/www/plugins/yaml/paquet.xml new file mode 100644 index 0000000..3b0b613 --- /dev/null +++ b/www/plugins/yaml/paquet.xml @@ -0,0 +1,19 @@ + + + YAML + + + yaml.org + Spyc + Symfony YAML - Fabien Potencier + + MIT + \ No newline at end of file diff --git a/www/plugins/yaml/plugin.xml b/www/plugins/yaml/plugin.xml new file mode 100644 index 0000000..c2e63a6 --- /dev/null +++ b/www/plugins/yaml/plugin.xml @@ -0,0 +1,19 @@ + + YAML + Un format de fichier simple pour éditer des listes de données. + format défini par yaml.org, librairie php développée par Fabien Potencier pour Symfony + MIT + 1.5.1 + stable + + Ce plugin fournit les fonctions de lecture/écriture du format YAML. + yaml_decode() et yaml_encode(). Il fournit aussi le format yaml pour la boucle (DATA). + + YAML + http://www.spip-contrib.net/Le-plugin-YAML + yaml.png + yaml_fonctions.php + + outil + + diff --git a/www/plugins/yaml/sfyaml/sfYaml.php b/www/plugins/yaml/sfyaml/sfYaml.php new file mode 100755 index 0000000..5a2be2e --- /dev/null +++ b/www/plugins/yaml/sfyaml/sfYaml.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfYaml offers convenience methods to load and dump YAML. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYaml.class.php 8988 2008-05-15 20:24:26Z fabien $ + */ +class sfYaml +{ + static protected + $spec = '1.2'; + + /** + * Sets the YAML specification version to use. + * + * @param string $version The YAML specification version + */ + static public function setSpecVersion($version) + { + if (!in_array($version, array('1.1', '1.2'))) + { + throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version)); + } + + self::$spec = $version; + } + + /** + * Gets the YAML specification version to use. + * + * @return string The YAML specification version + */ + static public function getSpecVersion() + { + return self::$spec; + } + + /** + * Loads YAML into a PHP array. + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. + * + * Usage: + * + * $array = sfYaml::load('config.yml'); + * print_r($array); + * + * + * @param string $input Path of YAML file or string containing YAML + * + * @return array The YAML converted to a PHP array + * + * @throws InvalidArgumentException If the YAML is not valid + */ + public static function load($input) + { + $file = ''; + + // if input is a file, load it + if (strpos($input, "\n") === false && is_file($input)) + { + $file = $input; + + $content = $yaml = file_get_contents($input); + + // if the file contains valid PHP, process it + if (strpos($content, '<'.'?') !== false + AND !(defined('_YAML_EVAL_PHP') AND !_YAML_EVAL_PHP)) + { + ob_start(); + $retval = eval('?'.'>'.$yaml); + $content = ob_get_clean(); + // syntax error? + if ($retval === FALSE) + $content = $yaml; + } + + // if an array is returned by the config file assume it's in plain php form else in YAML + $input = is_array($retval) ? $retval : $content; + } + + // if an array is returned by the config file assume it's in plain php form else in YAML + if (is_array($input)) + { + return $input; + } + + require_once dirname(__FILE__).'/sfYamlParser.php'; + + $yaml = new sfYamlParser(); + + try + { + $ret = $yaml->parse($input); + } + catch (Exception $e) + { + throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage())); + } + + return $ret; + } + + /** + * Dumps a PHP array to a YAML string. + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. + * + * @param array $array PHP array + * @param integer $inline The level where you switch to inline YAML + * + * @return string A YAML string representing the original PHP array + */ + public static function dump($array, $inline = 2) + { + require_once dirname(__FILE__).'/sfYamlDumper.php'; + + $yaml = new sfYamlDumper(); + + return $yaml->dump($array, $inline); + } +} + +/** + * Wraps echo to automatically provide a newline. + * + * @param string $string The string to echo with new line + */ +function echoln($string) +{ + echo $string."\n"; +} diff --git a/www/plugins/yaml/sfyaml/sfYamlDumper.php b/www/plugins/yaml/sfyaml/sfYamlDumper.php new file mode 100755 index 0000000..0ada2b3 --- /dev/null +++ b/www/plugins/yaml/sfyaml/sfYamlDumper.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once(dirname(__FILE__).'/sfYamlInline.php'); + +/** + * sfYamlDumper dumps PHP variables to YAML strings. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlDumper.class.php 10575 2008-08-01 13:08:42Z nicolas $ + */ +class sfYamlDumper +{ + /** + * Dumps a PHP value to YAML. + * + * @param mixed $input The PHP value + * @param integer $inline The level where you switch to inline YAML + * @param integer $indent The level o indentation indentation (used internally) + * + * @return string The YAML representation of the PHP value + */ + public function dump($input, $inline = 0, $indent = 0) + { + $output = ''; + $prefix = $indent ? str_repeat(' ', $indent) : ''; + + if ($inline <= 0 || !is_array($input) || empty($input)) + { + $output .= $prefix.sfYamlInline::dump($input); + } + else + { + $isAHash = array_keys($input) !== range(0, count($input) - 1); + + foreach ($input as $key => $value) + { + $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value); + + $output .= sprintf('%s%s%s%s', + $prefix, + $isAHash ? sfYamlInline::dump($key).':' : '-', + $willBeInlined ? ' ' : "\n", + $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2) + ).($willBeInlined ? "\n" : ''); + } + } + + return $output; + } +} diff --git a/www/plugins/yaml/sfyaml/sfYamlInline.php b/www/plugins/yaml/sfyaml/sfYamlInline.php new file mode 100755 index 0000000..f2e74bd --- /dev/null +++ b/www/plugins/yaml/sfyaml/sfYamlInline.php @@ -0,0 +1,424 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfYamlInline implements a YAML parser/dumper for the YAML inline syntax. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlInline.class.php 16177 2009-03-11 08:32:48Z fabien $ + */ +class sfYamlInline +{ + /** + * Convert a YAML string to a PHP array. + * + * @param string $value A YAML string + * + * @return array A PHP array representing the YAML string + */ + static public function load($value) + { + $value = trim($value); + + if (0 == strlen($value)) + { + return ''; + } + + switch ($value[0]) + { + case '[': + return self::parseSequence($value); + case '{': + return self::parseMapping($value); + default: + return self::parseScalar($value); + } + } + + /** + * Dumps a given PHP variable to a YAML string. + * + * @param mixed $value The PHP variable to convert + * + * @return string The YAML string representing the PHP array + */ + static public function dump($value) + { + $trueValues = '1.1' == sfYaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true'); + $falseValues = '1.1' == sfYaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false'); + + switch (true) + { + case is_resource($value): + throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.'); + case is_object($value): + return '!!php/object:'.serialize($value); + case is_array($value): + return self::dumpArray($value); + case null === $value: + return 'null'; + case true === $value: + return 'true'; + case false === $value: + return 'false'; + case ctype_digit($value): + return is_string($value) ? "'$value'" : (int) $value; + case is_numeric($value): + return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value); + case false !== strpos($value, "\n"): + return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value)); + case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \#] | \A[ - ? | < > = ! % @ ]/x', $value): + return sprintf("'%s'", str_replace('\'', '\'\'', $value)); + case '' == $value: + return "''"; + case preg_match(self::getTimestampRegex(), $value): + return "'$value'"; + case in_array(strtolower($value), $trueValues): + return "'$value'"; + case in_array(strtolower($value), $falseValues): + return "'$value'"; + case in_array(strtolower($value), array('null', '~')): + return "'$value'"; + default: + return $value; + } + } + + /** + * Dumps a PHP array to a YAML string. + * + * @param array $value The PHP array to dump + * + * @return string The YAML string representing the PHP array + */ + static protected function dumpArray($value) + { + // array + $keys = array_keys($value); + if ( + (1 == count($keys) && '0' == $keys[0]) + || + (count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2)) + { + $output = array(); + foreach ($value as $val) + { + $output[] = self::dump($val); + } + + return sprintf('[%s]', implode(', ', $output)); + } + + // mapping + $output = array(); + foreach ($value as $key => $val) + { + $output[] = sprintf('%s: %s', self::dump($key), self::dump($val)); + } + + return sprintf('{ %s }', implode(', ', $output)); + } + + /** + * Parses a scalar to a YAML string. + * + * @param scalar $scalar + * @param string $delimiters + * @param array $stringDelimiter + * @param integer $i + * @param boolean $evaluate + * + * @return string A YAML string + */ + static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true) + { + if (in_array($scalar[$i], $stringDelimiters)) + { + // quoted scalar + $output = self::parseQuotedScalar($scalar, $i); + + // skip next delimiter + ++$i; + } + else + { + // "normal" string + if (!$delimiters) + { + $output = substr($scalar, $i); + $i += strlen($output); + + // remove comments + if (false !== $strpos = strpos($output, ' #')) + { + $output = rtrim(substr($output, 0, $strpos)); + } + } + else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) + { + $output = $match[1]; + $i += strlen($output); + } + else + { + throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar)); + } + + $output = $evaluate ? self::evaluateScalar($output) : $output; + } + + return $output; + } + + /** + * Parses a quoted scalar to YAML. + * + * @param string $scalar + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseQuotedScalar($scalar, &$i) + { + $delimiter = $scalar[$i]; + ++$i; + $buffer = ''; + $len = strlen($scalar); + $escaped = '"' == $delimiter ? '\\"' : "''"; + + while ($i < $len) + { + if (isset($scalar[$i + 1]) && $escaped == $scalar[$i].$scalar[$i + 1]) + { + $buffer .= $delimiter; + ++$i; + } + else if ($delimiter == $scalar[$i]) + { + break; + } + else + { + $buffer .= $scalar[$i]; + } + + ++$i; + } + + if ('"' == $delimiter) + { + // evaluate the string + $buffer = str_replace(array('\\n', '\\r'), array("\n", "\r"), $buffer); + if (strpos($buffer,'\\x')!==false){ + $buffer = preg_replace_callback(',\\\\x([0-9a-f]+),', create_function('$m', 'return chr(hexdec($m[1]));'), $buffer); + } + } + + return $buffer; + } + + /** + * Parses a sequence to a YAML string. + * + * @param string $sequence + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseSequence($sequence, &$i = 0) + { + $output = array(); + $len = strlen($sequence); + $i += 1; + + // [foo, bar, ...] + while ($i < $len) + { + switch ($sequence[$i]) + { + case '[': + // nested sequence + $output[] = self::parseSequence($sequence, $i); + break; + case '{': + // nested mapping + $output[] = self::parseMapping($sequence, $i); + break; + case ']': + return $output; + case ',': + case ' ': + break; + default: + $isQuoted = in_array($sequence[$i], array('"', "'")); + $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i); + + if (!$isQuoted && false !== strpos($value, ': ')) + { + // embedded mapping? + try + { + $value = self::parseMapping('{'.$value.'}'); + } + catch (InvalidArgumentException $e) + { + // no, it's not + } + } + + $output[] = $value; + + --$i; + } + + ++$i; + } + + throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence)); + } + + /** + * Parses a mapping to a YAML string. + * + * @param string $mapping + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseMapping($mapping, &$i = 0) + { + $output = array(); + $len = strlen($mapping); + $i += 1; + + // {foo: bar, bar:foo, ...} + while ($i < $len) + { + switch ($mapping[$i]) + { + case ' ': + case ',': + ++$i; + continue 2; + case '}': + return $output; + } + + // key + $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false); + + // value + $done = false; + while ($i < $len) + { + switch ($mapping[$i]) + { + case '[': + // nested sequence + $output[$key] = self::parseSequence($mapping, $i); + $done = true; + break; + case '{': + // nested mapping + $output[$key] = self::parseMapping($mapping, $i); + $done = true; + break; + case ':': + case ' ': + break; + default: + $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i); + $done = true; + --$i; + } + + ++$i; + + if ($done) + { + continue 2; + } + } + } + + throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping)); + } + + /** + * Evaluates scalars and replaces magic values. + * + * @param string $scalar + * + * @return string A YAML string + */ + static protected function evaluateScalar($scalar) + { + $scalar = trim($scalar); + + $trueValues = '1.1' == sfYaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true'); + $falseValues = '1.1' == sfYaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false'); + + switch (true) + { + case 'null' == strtolower($scalar): + case '' == $scalar: + case '~' == $scalar: + return null; + case 0 === strpos($scalar, '!str'): + return (string) substr($scalar, 5); + case 0 === strpos($scalar, '! '): + return intval(self::parseScalar(substr($scalar, 2))); + case 0 === strpos($scalar, '!!php/object:'): + return unserialize(substr($scalar, 13)); + case ctype_digit($scalar): + $raw = $scalar; + $cast = intval($scalar); + return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw); + case in_array(strtolower($scalar), $trueValues): + return true; + case in_array(strtolower($scalar), $falseValues): + return false; + case is_numeric($scalar): + return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar); + case 0 == strcasecmp($scalar, '.inf'): + case 0 == strcasecmp($scalar, '.NaN'): + return -log(0); + case 0 == strcasecmp($scalar, '-.inf'): + return log(0); + case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): + return floatval(str_replace(',', '', $scalar)); + case preg_match(self::getTimestampRegex(), $scalar): + return strtotime($scalar); + default: + return (string) $scalar; + } + } + + static protected function getTimestampRegex() + { + return <<[0-9][0-9][0-9][0-9]) + -(?P[0-9][0-9]?) + -(?P[0-9][0-9]?) + (?:(?:[Tt]|[ \t]+) + (?P[0-9][0-9]?) + :(?P[0-9][0-9]) + :(?P[0-9][0-9]) + (?:\.(?P[0-9]*))? + (?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?) + (?::(?P[0-9][0-9]))?))?)? + $~x +EOF; + } +} diff --git a/www/plugins/yaml/sfyaml/sfYamlParser.php b/www/plugins/yaml/sfyaml/sfYamlParser.php new file mode 100755 index 0000000..baa5f76 --- /dev/null +++ b/www/plugins/yaml/sfyaml/sfYamlParser.php @@ -0,0 +1,540 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once(dirname(__FILE__).'/sfYamlInline.php'); + +/** + * sfYamlParser parses YAML strings to convert them to PHP arrays. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlParser.class.php 10832 2008-08-13 07:46:08Z fabien $ + */ +class sfYamlParser +{ + protected + $value = '', + $offset = 0, + $lines = array(), + $currentLineNb = -1, + $currentLine = '', + $refs = array(); + + /** + * Constructor + * + * @param integer $offset The offset of YAML document (used for line numbers in error messages) + */ + public function __construct($offset = 0) + { + $this->offset = $offset; + } + + /** + * Parses a YAML string to a PHP value. + * + * @param string $value A YAML string + * + * @return mixed A PHP value + * + * @throws InvalidArgumentException If the YAML is not valid + */ + public function parse($value) + { + $this->value = $this->cleanup($value); + $this->currentLineNb = -1; + $this->currentLine = ''; + $this->lines = explode("\n", $this->value); + + $data = array(); + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + continue; + } + + // tab? + if (preg_match('#^\t+#', $this->currentLine)) + { + throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + $isRef = $isInPlace = $isProcessed = false; + if (preg_match('#^\-(\s+(?P.+?))?\s*$#', $this->currentLine, $values)) + { + if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + // array + if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $data[] = $parser->parse($this->getNextEmbedBlock()); + } + else + { + if (preg_match('/^([^ ]+)\: +({.*?)$/', $values['value'], $matches)) + { + $data[] = array($matches[1] => sfYamlInline::load($matches[2])); + } + else + { + $data[] = $this->parseValue($values['value']); + } + } + } + else if (preg_match('#^(?P[^ ].*?) *\:(\s+(?P.+?))?\s*$#', $this->currentLine, $values)) + { + $key = sfYamlInline::parseScalar($values['key']); + + if ('<<' === $key) + { + if (isset($values['value']) && '*' === substr($values['value'], 0, 1)) + { + $isInPlace = substr($values['value'], 1); + if (!array_key_exists($isInPlace, $this->refs)) + { + throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + else + { + if (isset($values['value']) && $values['value'] !== '') + { + $value = $values['value']; + } + else + { + $value = $this->getNextEmbedBlock(); + } + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $parsed = $parser->parse($value); + + $merged = array(); + if (!is_array($parsed)) + { + throw new InvalidArgumentException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + else if (isset($parsed[0])) + { + // Numeric array, merge individual elements + foreach (array_reverse($parsed) as $parsedItem) + { + if (!is_array($parsedItem)) + { + throw new InvalidArgumentException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem)); + } + $merged = array_merge($parsedItem, $merged); + } + } + else + { + // Associative array, merge + $merged = array_merge($merge, $parsed); + } + + $isProcessed = $merged; + } + } + else if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + if ($isProcessed) + { + // Merge keys + $data = $isProcessed; + } + // hash + else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + // if next line is less indented or equal, then it means that the current value is null + if ($this->isNextLineIndented()) + { + $data[$key] = null; + } + else + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $data[$key] = $parser->parse($this->getNextEmbedBlock()); + } + } + else + { + if ($isInPlace) + { + $data = $this->refs[$isInPlace]; + } + else + { + $data[$key] = $this->parseValue($values['value']); + } + } + } + else + { + // one liner? + if (1 == count(explode("\n", rtrim($this->value, "\n")))) + { + $value = sfYamlInline::load($this->lines[0]); + if (is_array($value)) + { + $first = reset($value); + if ('*' === substr($first, 0, 1)) + { + $data = array(); + foreach ($value as $alias) + { + $data[] = $this->refs[substr($alias, 1)]; + } + $value = $data; + } + } + + return $value; + } + + throw new InvalidArgumentException(sprintf('Unable to parse line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + if ($isRef) + { + $this->refs[$isRef] = end($data); + } + } + + return empty($data) ? null : $data; + } + + /** + * Returns the current line number (takes the offset into account). + * + * @return integer The current line number + */ + protected function getRealCurrentLineNb() + { + return $this->currentLineNb + $this->offset; + } + + /** + * Returns the current line indentation. + * + * @return integer The current line indentation + */ + protected function getCurrentLineIndentation() + { + return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' ')); + } + + /** + * Returns the next embed block of YAML. + * + * @return string A YAML string + */ + protected function getNextEmbedBlock() + { + $this->moveToNextLine(); + + $newIndent = $this->getCurrentLineIndentation(); + + if (!$this->isCurrentLineEmpty() && 0 == $newIndent) + { + throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + $data = array(substr($this->currentLine, $newIndent)); + + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + if ($this->isCurrentLineBlank()) + { + $data[] = substr($this->currentLine, $newIndent); + } + + continue; + } + + $indent = $this->getCurrentLineIndentation(); + + if (preg_match('#^(?P *)$#', $this->currentLine, $match)) + { + // empty line + $data[] = $match['text']; + } + else if ($indent >= $newIndent) + { + $data[] = substr($this->currentLine, $newIndent); + } + else if (0 == $indent) + { + $this->moveToPreviousLine(); + + break; + } + else + { + throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + + return implode("\n", $data); + } + + /** + * Moves the parser to the next line. + */ + protected function moveToNextLine() + { + if ($this->currentLineNb >= count($this->lines) - 1) + { + return false; + } + + $this->currentLine = $this->lines[++$this->currentLineNb]; + + return true; + } + + /** + * Moves the parser to the previous line. + */ + protected function moveToPreviousLine() + { + $this->currentLine = $this->lines[--$this->currentLineNb]; + } + + /** + * Parses a YAML value. + * + * @param string $value A YAML value + * + * @return mixed A PHP value + */ + protected function parseValue($value) + { + if ('*' === substr($value, 0, 1)) + { + if (false !== $pos = strpos($value, '#')) + { + $value = substr($value, 1, $pos - 2); + } + else + { + $value = substr($value, 1); + } + + if (!array_key_exists($value, $this->refs)) + { + throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine)); + } + return $this->refs[$value]; + } + + if (preg_match('/^(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?$/', $value, $matches)) + { + $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : ''; + + return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers))); + } + else + { + return sfYamlInline::load($value); + } + } + + /** + * Parses a folded scalar. + * + * @param string $separator The separator that was used to begin this folded scalar (| or >) + * @param string $indicator The indicator that was used to begin this folded scalar (+ or -) + * @param integer $indentation The indentation that was used to begin this folded scalar + * + * @return string The text value + */ + protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0) + { + $separator = '|' == $separator ? "\n" : ' '; + $text = ''; + + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineBlank()) + { + $text .= "\n"; + + $notEOF = $this->moveToNextLine(); + } + + if (!$notEOF) + { + return ''; + } + + if (!preg_match('#^(?P'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P.*)$#', $this->currentLine, $matches)) + { + $this->moveToPreviousLine(); + + return ''; + } + + $textIndent = $matches['indent']; + $previousIndent = 0; + + $text .= $matches['text'].$separator; + while ($this->currentLineNb + 1 < count($this->lines)) + { + $this->moveToNextLine(); + + if (preg_match('#^(?P {'.strlen($textIndent).',})(?P.+)$#', $this->currentLine, $matches)) + { + if (' ' == $separator && $previousIndent != $matches['indent']) + { + $text = substr($text, 0, -1)."\n"; + } + $previousIndent = $matches['indent']; + + $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator); + } + else if (preg_match('#^(?P *)$#', $this->currentLine, $matches)) + { + $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n"; + } + else + { + $this->moveToPreviousLine(); + + break; + } + } + + if (' ' == $separator) + { + // replace last separator by a newline + $text = preg_replace('/ (\n*)$/', "\n$1", $text); + } + + switch ($indicator) + { + case '': + $text = preg_replace('#\n+$#s', "\n", $text); + break; + case '+': + break; + case '-': + $text = preg_replace('#\n+$#s', '', $text); + break; + } + + return $text; + } + + /** + * Returns true if the next line is indented. + * + * @return Boolean Returns true if the next line is indented, false otherwise + */ + protected function isNextLineIndented() + { + $currentIndentation = $this->getCurrentLineIndentation(); + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineEmpty()) + { + $notEOF = $this->moveToNextLine(); + } + + if (false === $notEOF) + { + return false; + } + + $ret = false; + if ($this->getCurrentLineIndentation() <= $currentIndentation) + { + $ret = true; + } + + $this->moveToPreviousLine(); + + return $ret; + } + + /** + * Returns true if the current line is blank or if it is a comment line. + * + * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise + */ + protected function isCurrentLineEmpty() + { + return $this->isCurrentLineBlank() || $this->isCurrentLineComment(); + } + + /** + * Returns true if the current line is blank. + * + * @return Boolean Returns true if the current line is blank, false otherwise + */ + protected function isCurrentLineBlank() + { + return '' == trim($this->currentLine, ' '); + } + + /** + * Returns true if the current line is a comment line. + * + * @return Boolean Returns true if the current line is a comment line, false otherwise + */ + protected function isCurrentLineComment() + { + //checking explicitly the first char of the trim is faster than loops or strpos + $ltrimmedLine = ltrim($this->currentLine, ' '); + return $ltrimmedLine[0] === '#'; + } + + /** + * Cleanups a YAML string to be parsed. + * + * @param string $value The input YAML string + * + * @return string A cleaned up YAML string + */ + protected function cleanup($value) + { + $value = str_replace(array("\r\n", "\r"), "\n", $value); + + if (!preg_match("#\n$#", $value)) + { + $value .= "\n"; + } + + // strip YAML header + preg_replace('#^\%YAML[: ][\d\.]+.*\n#s', '', $value); + + // remove --- + $value = preg_replace('#^\-\-\-.*?\n#s', '', $value); + + return $value; + } +} diff --git a/www/plugins/yaml/spyc/spyc-php4.php b/www/plugins/yaml/spyc/spyc-php4.php new file mode 100644 index 0000000..9329268 --- /dev/null +++ b/www/plugins/yaml/spyc/spyc-php4.php @@ -0,0 +1,1024 @@ + + * @author Chris Wanstrath + * @link http://code.google.com/p/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * + * or: + * + * $array = Spyc::YAMLLoad($file); + * + * or: + * + * $array = spyc_load_file($file); + * + * @package Spyc + */ +class Spyc { + + // SETTINGS + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + var $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + var $setting_use_syck_is_possible = false; + + + + /**#@+ + * @access private + * @var mixed + */ + var $_dumpIndent; + var $_dumpWordWrap; + var $_containsGroupAnchor = false; + var $_containsGroupAlias = false; + var $path; + var $result; + var $LiteralPlaceHolder = '___YAML_Literal_Block___'; + var $SavedGroups = array(); + var $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + var $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + var $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + function load ($input) { + return $this->__loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + function loadFile ($file) { + return $this->__load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + */ + function YAMLLoad($input) { + $Spyc = new Spyc; + return $Spyc->__load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * + * @access public + * @return array + * @param string $input String containing YAML + */ + function YAMLLoadString($input) { + $Spyc = new Spyc; + return $Spyc->__loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + function YAMLDump($array,$indent = false,$wordwrap = false) { + $spyc = new Spyc; + return $spyc->dump($array,$indent,$wordwrap); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + function dump($array,$indent = false,$wordwrap = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $first_key = key($array); + + $previous_key = -1; + foreach ($array as $key => $value) { + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0) { + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, NULL, $indent, $previous_key, $first_key); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + $first_key = key($array); + foreach ($array as $key => $value) { + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || substr ($value, -1, 1) == ':')) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + if (is_bool($value)) { + $value = ($value) ? "true" : "false"; + } + } + + if ($value === array()) $value = '[ ]'; + + $spaces = str_repeat(' ',$indent); + + if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + // Ligne ci-dessous désactivée car non compatible PHP4 + //if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false) { $key = '"' . $key . '"'; } + $string = $spaces.$key.': '.$value."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + function _doLiteralBlock($value,$indent) { + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $newValue .= "\n" . $spaces . trim($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value)) + $value = '"' . $value . '"'; + } + + + return $value; + } + +// LOADING FUNCTIONS + + function __load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + function __loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ('', $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = $this->stripIndent($line, $this->indent); + if ($this->isComment($line)) continue; + if ($this->isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = $this->startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= $this->LiteralPlaceHolder; + + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle); + } + $i--; + } + + while (++$i < $cnt && $this->greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + + + if (strpos ($line, '#')) { + if (strpos ($line, '"') === false && strpos ($line, "'") === false) + $line = preg_replace('/\s+#(.+)$/','',$line); + } + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + return file($input); + + return $this->loadFromString($input); + } + + function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + + if (!$line) return array(); + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) + return $this->returnMappedSequence($line); + + if ($this->startsMappedValue($line)) + return $this->returnMappedValue($line); + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + function _toType($value) { + if ($value === '') return null; + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); + + if (strpos($value, ' #') !== false) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if (intval($first_character) > 0 && preg_match ('/^[1-9]+[0-9]*$/', $value)) { + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if (in_array($value, + array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) { + return true; + } + + if (in_array(strtolower($value), + array('false', 'off', '-', 'no', 'n'))) { + return false; + } + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (trim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(', ',$inline); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + return $explode; + } + + function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + function addLiteralLine ($literalBlock, $line, $literalBlockStyle) { + $line = $this->stripIndent($line); + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + function isEmpty ($line) { + return (trim ($line) === ''); + } + + + function isArrayElement ($line) { + if (!$line) return false; + if ($line[0] != '-') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + function isHashElement ($line) { + return strpos($line, ':'); + } + + function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + function startsMappedSequence ($line) { + return ($line[0] == '-' && substr ($line, -1, 1) == ':'); + } + + function returnMappedSequence ($line) { + $array = array(); + $key = $this->unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + function returnMappedValue ($line) { + $array = array(); + $key = $this->unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + function returnPlainArray ($line) { + return $this->_toType($line); + } + + function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ':')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(':',$line); + $key = trim($explode[0]); + array_shift($explode); + $value = trim(implode(':',$explode)); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + $array[] = $value; + return $array; + } + + + function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} + +// Enable use of Spyc from command line +// The syntax is the following: php spyc.php spyc.yaml + +define ('SPYC_FROM_COMMAND_LINE', false); + +do { + if (!SPYC_FROM_COMMAND_LINE) break; + if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; + if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break; + $file = $argv[1]; + printf ("Spyc loading file: %s\n", $file); + print_r (spyc_load_file ($file)); +} while (0); \ No newline at end of file diff --git a/www/plugins/yaml/spyc/spyc.php b/www/plugins/yaml/spyc/spyc.php new file mode 100644 index 0000000..e19d562 --- /dev/null +++ b/www/plugins/yaml/spyc/spyc.php @@ -0,0 +1,1046 @@ + + * @author Chris Wanstrath + * @link http://code.google.com/p/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * + * or: + * + * $array = Spyc::YAMLLoad($file); + * + * or: + * + * $array = spyc_load_file($file); + * + * @package Spyc + */ +class Spyc { + + // SETTINGS + + const REMPTY = "\0\0\0\0\0"; + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + public $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_use_syck_is_possible = false; + + + + /**#@+ + * @access private + * @var mixed + */ + private $_dumpIndent; + private $_dumpWordWrap; + private $_containsGroupAnchor = false; + private $_containsGroupAlias = false; + private $path; + private $result; + private $LiteralPlaceHolder = '___YAML_Literal_Block___'; + private $SavedGroups = array(); + private $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + private $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + public $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + public function load ($input) { + return $this->__loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + public function loadFile ($file) { + return $this->__load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + */ + public static function YAMLLoad($input) { + $Spyc = new Spyc; + return $Spyc->__load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * + * @access public + * @return array + * @param string $input String containing YAML + */ + public static function YAMLLoadString($input) { + $Spyc = new Spyc; + return $Spyc->__loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public static function YAMLDump($array,$indent = false,$wordwrap = false) { + $spyc = new Spyc; + return $spyc->dump($array,$indent,$wordwrap); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public function dump($array,$indent = false,$wordwrap = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + private function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || + substr ($value, -1, 1) == ':') + ) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + } + + if ($value === array()) $value = '[ ]'; + if (in_array ($value, array ('true', 'TRUE', 'false', 'FALSE', 'y', 'Y', 'n', 'N', 'null', 'NULL'), true)) { + $value = $this->_doLiteralBlock($value,$indent); + } + if (trim ($value) != $value) + $value = $this->_doLiteralBlock($value,$indent); + + if (is_bool($value)) { + $value = ($value) ? "true" : "false"; + } + + if ($value === null) $value = 'null'; + if ($value === "'" . self::REMPTY . "'") $value = null; + + $spaces = str_repeat(' ',$indent); + + //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } + $string = rtrim ($spaces.$key.': '.$value)."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + private function _doLiteralBlock($value,$indent) { + if ($value === "\n") return '\n'; + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $newValue .= "\n" . $spaces . ($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + private function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) + $value = '"' . $value . '"'; + } + + + return $value; + } + +// LOADING FUNCTIONS + + private function __load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + private function __loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + private function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ('', $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = self::stripIndent($line, $this->indent); + if (self::isComment($line)) continue; + if (self::isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = self::startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= $this->LiteralPlaceHolder; + $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); + } + $i--; + } + + while (++$i < $cnt && self::greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + + + if (strpos ($line, '#')) { + if (strpos ($line, '"') === false && strpos ($line, "'") === false) + $line = preg_replace('/\s+#(.+)$/','',$line); + } + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + private function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + return file($input); + + return $this->loadFromString($input); + } + + private function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + private function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + if (!$line) return array(); + + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) + return $this->returnMappedSequence($line); + + if ($this->startsMappedValue($line)) + return $this->returnMappedValue($line); + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + private function _toType($value) { + if ($value === '') return null; + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); + + if (strpos($value, ' #') !== false && !$is_quoted) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if (!$is_quoted) $value = str_replace('\n', "\n", $value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if (in_array($value, + array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) { + return true; + } + + if (in_array(strtolower($value), + array('false', 'off', '-', 'no', 'n'))) { + return false; + } + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (rtrim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + private function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(', ',$inline); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + return $explode; + } + + private function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + private function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + private function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + private function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + if (!is_array ($_arr)) + $_arr = array ($key=>$value); + else + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + private static function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + private static function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { + $line = self::stripIndent($line, $indent); + if ($literalBlockStyle !== '|') { + $line = self::stripIndent($line); + } + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + private static function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + private function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + private function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + private static function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + private static function isEmpty ($line) { + return (trim ($line) === ''); + } + + + private function isArrayElement ($line) { + if (!$line) return false; + if ($line[0] != '-') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + private function isHashElement ($line) { + return strpos($line, ':'); + } + + private function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + private static function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + private function startsMappedSequence ($line) { + return ($line[0] == '-' && substr ($line, -1, 1) == ':'); + } + + private function returnMappedSequence ($line) { + $array = array(); + $key = self::unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + private function returnMappedValue ($line) { + $array = array(); + $key = self::unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + private function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + private function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + private function returnPlainArray ($line) { + return $this->_toType($line); + } + + private function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ':')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(':',$line); + $key = trim($explode[0]); + array_shift($explode); + $value = trim(implode(':',$explode)); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + private function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + $array[] = $value; + return $array; + } + + + private function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + private function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + private function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} + +// Enable use of Spyc from command line +// The syntax is the following: php spyc.php spyc.yaml + +define ('SPYC_FROM_COMMAND_LINE', false); + +do { + if (!SPYC_FROM_COMMAND_LINE) break; + if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; + if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break; + $file = $argv[1]; + printf ("Spyc loading file: %s\n", $file); + print_r (spyc_load_file ($file)); +} while (0); \ No newline at end of file diff --git a/www/plugins/yaml/svn.revision b/www/plugins/yaml/svn.revision new file mode 100644 index 0000000..4049a97 --- /dev/null +++ b/www/plugins/yaml/svn.revision @@ -0,0 +1,10 @@ + + +Origine: file:///home/svn/repository/spip-zone/_plugins_/yaml +Revision: 78336 +Dernier commit: 2013-11-11 00:00:50 +0100 + +file:///home/svn/repository/spip-zone/_plugins_/yaml +78336 +2013-11-11 00:00:50 +0100 + \ No newline at end of file diff --git a/www/plugins/yaml/yaml.png b/www/plugins/yaml/yaml.png new file mode 100644 index 0000000000000000000000000000000000000000..9c14d44ac5fae48796497a1d25d77bf784dda29e GIT binary patch literal 12232 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 -- 2.20.1