diff --git a/data/spyc.php b/data/Spyc.php similarity index 83% rename from data/spyc.php rename to data/Spyc.php index 47d5877..49e0cbb 100644 --- a/data/spyc.php +++ b/data/Spyc.php @@ -1,10 +1,10 @@ * @author Chris Wanstrath - * @link http://code.google.com/p/spyc/ + * @link https://github.com/mustangostang/spyc/ * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen * @license http://www.opensource.org/licenses/mit-license.php MIT License * @package Spyc @@ -32,6 +32,19 @@ if (!function_exists('spyc_load_file')) { } } +if (!function_exists('spyc_dump')) { + /** + * Dumps array to YAML. + * @param array $data Array. + * @return string + */ + function spyc_dump ($data) { + return Spyc::YAMLDump($data, false, false, true); + } +} + +if (!class_exists('Spyc')) { + /** * The Simple PHP YAML Class. * @@ -108,7 +121,7 @@ class Spyc { * @return array */ public function load ($input) { - return $this->__loadString($input); + return $this->_loadString($input); } /** @@ -117,7 +130,7 @@ class Spyc { * @return array */ public function loadFile ($file) { - return $this->__load($file); + return $this->_load($file); } /** @@ -137,7 +150,7 @@ class Spyc { */ public static function YAMLLoad($input) { $Spyc = new Spyc; - return $Spyc->__load($input); + return $Spyc->_load($input); } /** @@ -161,7 +174,7 @@ class Spyc { */ public static function YAMLLoadString($input) { $Spyc = new Spyc; - return $Spyc->__loadString($input); + return $Spyc->_loadString($input); } /** @@ -180,13 +193,14 @@ class Spyc { * * @access public * @return string - * @param array $array PHP array + * @param array|\stdClass $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) + * @param bool $no_opening_dashes Do not start YAML file with "---\n" */ - public static function YAMLDump($array,$indent = false,$wordwrap = false) { + public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) { $spyc = new Spyc; - return $spyc->dump($array,$indent,$wordwrap); + return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes); } @@ -210,7 +224,7 @@ class Spyc { * @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) { + public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) { // Dumps to some very clean YAML. We'll have to add some more features // and options soon. And better support for folding. @@ -228,7 +242,8 @@ class Spyc { } // New YAML document - $string = "---\n"; + $string = ""; + if (!$no_opening_dashes) $string = "---\n"; // Start at the base of the array and move through it. if ($array) { @@ -252,6 +267,7 @@ class Spyc { * @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_object($value)) $value = (array)$value; if (is_array($value)) { if (empty ($value)) return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); @@ -302,7 +318,7 @@ class Spyc { 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,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || substr ($value, -1, 1) == ':') ) { @@ -312,14 +328,15 @@ class Spyc { } 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 ($value === "") $value = '""'; + if (self::isTranslationWord($value)) { + $value = $this->_doLiteralBlock($value, $indent); } if (trim ($value) != $value) $value = $this->_doLiteralBlock($value,$indent); if (is_bool($value)) { - $value = ($value) ? "true" : "false"; + $value = $value ? "true" : "false"; } if ($value === null) $value = 'null'; @@ -357,9 +374,17 @@ class Spyc { } $exploded = explode("\n",$value); $newValue = '|'; - $indent += $this->_dumpIndent; + if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) { + $newValue = $exploded[0]; + unset($exploded[0]); + } + $indent += $this->_dumpIndent; $spaces = str_repeat(' ',$indent); foreach ($exploded as $line) { + $line = trim($line); + if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line)-1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line)-1)) { + $line = substr($line, 1, -1); + } $newValue .= "\n" . $spaces . ($line); } return $newValue; @@ -382,20 +407,76 @@ class Spyc { } else { if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) $value = '"' . $value . '"'; + if (is_numeric($value) && is_string($value)) + $value = '"' . $value . '"'; } return $value; } + private function isTrueWord($value) { + $words = self::getTranslations(array('true', 'on', 'yes', 'y')); + return in_array($value, $words, true); + } + + private function isFalseWord($value) { + $words = self::getTranslations(array('false', 'off', 'no', 'n')); + return in_array($value, $words, true); + } + + private function isNullWord($value) { + $words = self::getTranslations(array('null', '~')); + return in_array($value, $words, true); + } + + private function isTranslationWord($value) { + return ( + self::isTrueWord($value) || + self::isFalseWord($value) || + self::isNullWord($value) + ); + } + + /** + * Coerce a string into a native type + * Reference: http://yaml.org/type/bool.html + * TODO: Use only words from the YAML spec. + * @access private + * @param $value The value to coerce + */ + private function coerceValue(&$value) { + if (self::isTrueWord($value)) { + $value = true; + } else if (self::isFalseWord($value)) { + $value = false; + } else if (self::isNullWord($value)) { + $value = null; + } + } + + /** + * Given a set of words, perform the appropriate translations on them to + * match the YAML 1.1 specification for type coercing. + * @param $words The words to translate + * @access private + */ + private static function getTranslations(array $words) { + $result = array(); + foreach ($words as $i) { + $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i))); + } + return $result; + } + // LOADING FUNCTIONS - private function __load($input) { + private function _load($input) { $Source = $this->loadFromSource($input); return $this->loadWithSource($Source); } - private function __loadString($input) { + private function _loadString($input) { $Source = $this->loadFromString($input); return $this->loadWithSource($Source); } @@ -403,7 +484,7 @@ class Spyc { 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)); + $array = syck_load (implode ("\n", $Source)); return is_array($array) ? $array : array(); } @@ -425,7 +506,7 @@ class Spyc { if ($literalBlockStyle) { $line = rtrim ($line, $literalBlockStyle . " \n"); $literalBlock = ''; - $line .= $this->LiteralPlaceHolder; + $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); @@ -433,18 +514,16 @@ class Spyc { $i--; } + // Strip out comments + if (strpos ($line, '#')) { + $line = preg_replace('/\s*#([^"\']+)$/','',$line); + } + 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) @@ -463,7 +542,7 @@ class Spyc { private function loadFromSource ($input) { if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) - return file($input); + $input = file_get_contents($input); return $this->loadFromString($input); } @@ -519,7 +598,7 @@ class Spyc { * @return mixed */ private function _toType($value) { - if ($value === '') return null; + if ($value === '') return ""; $first_character = $value[0]; $last_character = substr($value, -1, 1); @@ -531,14 +610,16 @@ class Spyc { $is_quoted = true; } while (0); - if ($is_quoted) - return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); + if ($is_quoted) { + $value = str_replace('\n', "\n", $value); + if ($first_character == "'") + return strtr(substr ($value, 1, -1), array ('\'\'' => '\'', '\\\''=> '\'')); + 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)); @@ -586,20 +667,17 @@ class Spyc { if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ $intvalue = (int)$value; - if ($intvalue != PHP_INT_MAX) + if ($intvalue != PHP_INT_MAX && $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 ( is_string($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) { + // Hexadecimal value. + return hexdec($value); } - if (in_array(strtolower($value), - array('false', 'off', '-', 'no', 'n'))) { - return false; - } + $this->coerceValue($value); if (is_numeric($value)) { if ($value === '0') return 0; @@ -625,6 +703,15 @@ class Spyc { $seqs = array(); $maps = array(); $saved_strings = array(); + $saved_empties = array(); + + // Check for empty strings + $regex = '/("")|(\'\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_empties = $strings[0]; + $inline = preg_replace($regex,'YAMLEmpty',$inline); + } + unset($regex); // Check for strings $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; @@ -634,6 +721,8 @@ class Spyc { } unset($regex); + // echo $inline; + $i = 0; do { @@ -653,7 +742,8 @@ class Spyc { } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); - $explode = explode(', ',$inline); + $explode = explode(',',$inline); + $explode = array_map('trim', $explode); $stringi = 0; $i = 0; while (1) { @@ -695,6 +785,17 @@ class Spyc { } } + + // Re-add the empties + if (!empty($saved_empties)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLEmpty') !== false) { + $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1); + $value = $explode[$key]; + } + } + } + $finished = true; foreach ($explode as $key => $value) { if (strpos($value,'YAMLSeq') !== false) { @@ -706,6 +807,9 @@ class Spyc { if (strpos($value,'YAMLString') !== false) { $finished = false; break; } + if (strpos($value,'YAMLEmpty') !== false) { + $finished = false; break; + } } if ($finished) break; @@ -714,6 +818,7 @@ class Spyc { break; // Prevent infinite loops. } + return $explode; } @@ -787,7 +892,7 @@ class Spyc { if (!is_array ($_arr)) { $_arr = array (); } $_arr = array_merge ($_arr, $value); - } elseif ($key || $key === '' || $key === '0') { + } else if ($key || $key === '' || $key === '0') { if (!is_array ($_arr)) $_arr = array ($key=>$value); else @@ -862,7 +967,7 @@ class Spyc { foreach ($lineArray as $k => $_) { if (is_array($_)) $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); - elseif (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) $lineArray[$k] = rtrim ($literalBlock, " \r\n"); } return $lineArray; @@ -911,8 +1016,8 @@ class Spyc { private function isArrayElement ($line) { - if (!$line) return false; - if ($line[0] != '-') return false; + if (!$line || !is_scalar($line)) return false; + if (substr($line, 0, 2) != '- ') return false; if (strlen ($line) > 3) if (substr($line,0,3) == '---') return false; @@ -939,7 +1044,7 @@ class Spyc { } private function startsMappedSequence ($line) { - return ($line[0] == '-' && substr ($line, -1, 1) == ':'); + return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':'); } private function returnMappedSequence ($line) { @@ -950,7 +1055,16 @@ class Spyc { return array($array); } + private function checkKeysInValue($value) { + if (strchr('[{"\'', $value[0]) === false) { + if (strchr($value, ': ') !== false) { + throw new Exception('Too many keys: '.$value); + } + } + } + private function returnMappedValue ($line) { + $this->checkKeysInValue($line); $array = array(); $key = self::unquote (trim(substr($line,0,-1))); $array[$key] = ''; @@ -972,7 +1086,7 @@ class Spyc { private function returnKeyValuePair ($line) { $array = array(); $key = ''; - if (strpos ($line, ':')) { + 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)) { @@ -980,10 +1094,10 @@ class Spyc { $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)); + $explode = explode(': ', $line); + $key = trim(array_shift($explode)); + $value = trim(implode(': ', $explode)); + $this->checkKeysInValue($value); } // Set the type of the value. Int, string, etc $value = $this->_toType($value); @@ -1002,6 +1116,9 @@ class Spyc { $array = array(); $value = trim(substr($line,1)); $value = $this->_toType($value); + if ($this->isArrayElement($value)) { + $value = $this->returnArrayElement($value); + } $array[] = $value; return $array; } @@ -1030,17 +1147,15 @@ class Spyc { 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); +// The syntax is the following: php Spyc.php spyc.yaml do { - if (!SPYC_FROM_COMMAND_LINE) break; + if (PHP_SAPI != 'cli') break; if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; - if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break; + if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_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 + echo json_encode (spyc_load_file ($file)); +} while (0); diff --git a/data/ulsdata2json.php b/data/ulsdata2json.php index 8abf048..1ba7cf3 100644 --- a/data/ulsdata2json.php +++ b/data/ulsdata2json.php @@ -18,7 +18,7 @@ * @licence MIT License */ -include __DIR__ . '/spyc.php'; +include __DIR__ . '/Spyc.php'; print "Reading langdb.yaml...\n"; $yamlLangdb = file_get_contents( 'langdb.yaml' );