function ParseIt($data, $name = 'theater', $path = '', $level = 0) { global $ordered_fields, $object_fields; $out = array(); // Figure out if we are dealing with named objects, or section names // If this is an ordered field, parse the sub-items $path = $path ? "{$path}/{$name}" : $name; $objects = matchTheaterPath($path, $object_fields); $ordered = matchTheaterPath($path, $ordered_fields); // echo "path: {$path} ordered: {$ordered}\n"; if ($ordered) { $items = array(); foreach ($data as $idx => $item) { foreach ($item as $key => $val) { $items[$key] = $val; } } } else { $items = $data; } foreach ($items as $key => $val) { $title = $objects ? "@name" : $key; if (is_array($val)) { $pdata = ParseIt($val, $title, $path, $level + 1); if (isset($out[$title])) { $pdata = theater_array_replace_recursive($out[$title], $pdata); } $out[$title] = $pdata; uksort($out[$title], "strnatcasecmp"); } else { $out[$title] = vartype($val); } } uksort($out, "strnatcasecmp"); return $out; }
function parseKeyValues($KVString, $fixquotes = true, $debug = false) { global $ordered_fields, $theater_conditions, $allow_duplicates_fields; // Escape all non-quoted values if ($fixquotes) { $KVString = preg_replace('/^(\\s*)([a-zA-Z]+)/m', '${1}"${2}"', $KVString); } $KVString = preg_replace('/^(\\s+)/m', '', $KVString); $KVLines = preg_split('/\\n|\\r\\n?/', $KVString); $len = strlen($KVString); // if ($debug) $len = 2098; $stack = array(); $isInQuote = false; $quoteKey = ""; $quoteValue = ""; $quoteWhat = "key"; $lastKey = ""; $lastPath = ""; $lastValue = ""; $lastLine = ""; $keys = array(); $comments = array(); $commentLines = 1; $ptr =& $stack; $c = ""; $line = 1; $parents = array(&$ptr); $tree = array(); $path = ""; $sequential = ''; $sequential_path = ''; $conditional = ''; $conditional_path = ''; $allowdupes = ''; for ($i = 0; $i < $len; $i++) { $l = $c; $c = $KVString[$i]; // current char switch ($c) { case "\"": $commentLines = 1; if ($isInQuote) { // EDIT: Use quoteWhat as a qualifier rather than quoteValue in case we have a "" value if (strlen($quoteKey) && $quoteWhat == "value") { if ($sequential) { if (!$allowdupes) { // Check to make sure this value does not already exist if (is_array($ptr)) { foreach ($ptr as $item) { if (isset($item[$quoteKey])) { if ($item[$quoteKey] == $quoteValue) { $quoteValue = ''; } } } } } if ($quoteValue) { $ptr[] = array($quoteKey => TypecastValue($quoteValue)); } } else { // If this value is already set, make it an array if (isset($ptr[$quoteKey])) { // If the item is not already an array, make it one if (!is_array($ptr[$quoteKey])) { $ptr[$quoteKey] = array($ptr[$quoteKey]); } // Add this value to the end of the array $ptr[$quoteKey][] = TypecastValue($quoteValue); } else { // Set the value otherwise $ptr[$quoteKey] = TypecastValue($quoteValue); } } $lastLine = $line; $lastPath = "{$path}/{$quoteKey}"; $lastKey = $quoteKey; $quoteKey = ""; $quoteValue = ""; } if ($quoteWhat == "key") { $quoteWhat = "value"; } else { if ($quoteWhat == "value") { $quoteWhat = "key"; } } } $isInQuote = !$isInQuote; break; // Start new section // Start new section case "{": $commentLines = 1; if (strlen($quoteKey)) { if (substr($quoteKey, 0, 1) == '?') { $conditional = $quoteKey; $conditional_path = $path; } else { // Add key to tree $tree[] = $quoteKey; // Update path in tree $path = implode("/", $tree); if ($conditional) { $theater_conditions[$conditional][] = $path; } $sequential = matchTheaterPath($path, $ordered_fields); if (!$sequential_path && $sequential) { $sequential_path = $path; // echo "sequential {$sequential} path {$path} sequential_path {$sequential_path}\n"; } if (!$allowdupes) { // echo "test allowdupes\n"; $allowdupes = matchTheaterPath($path, $allow_duplicates_fields); // echo "allowdupes {$allowdupes}\n"; } // Update parents array with current pointer in the new path location $parents[$path] =& $ptr; // If the object already exists, create an array of objects if ($quoteKey[0] == '?') { $ptr =& $ptr[][$quoteKey]; } elseif (isset($ptr[$quoteKey])) { // Get all the keys, this assumes that the data will have non-numeric keys. $keys = implode('', array_keys($ptr[$quoteKey])); // So when we see non-numeric keys, we push the existing data into an array of itself before appending the next object. if (!is_numeric($keys)) { $ptr[$quoteKey] = array($ptr[$quoteKey]); } // Move the pointer to a new array under the key $ptr =& $ptr[$quoteKey][]; } else { // Just put the object here if there is no existing object $ptr =& $ptr[$quoteKey]; } $lastPath = "{$path}/{$quoteKey}"; $lastKey = $quoteKey; } $quoteKey = ""; $quoteWhat = "key"; } $lastLine = $line; break; // End of section // End of section case "}": $commentLines = 1; // Move pointer back to the parent if ($conditional_path != $path) { $sequential = ''; if ($path == $allowdupes) { $allowdupes = ''; // echo "done allowdupes\n"; } if ($sequential) { // echo "} sequential {$sequential} path {$path} sequential_path {$sequential_path}\n"; if ($path == $sequential_path) { // echo "unset\n"; $sequential_path = ''; } } $ptr =& $parents[$path]; // Take last element off tree as we back out array_pop($tree); // Update path now that we have backed out $path = implode("/", $tree); } else { $conditional = ''; $conditional_path = ''; } $lastLine = $line; break; case "\t": break; case "/": // Comment "// " or "/*" if ($KVString[$i + 1] == "/" || $KVString[$i + 1] == "*") { $comment = ""; // Get comment type $ctype = $KVString[$i + 1]; while ($i < $len) { // If type is "// " stop processing at newline if ($ctype == '/' && $KVString[$i + 1] == "\n") { // $i+=2; break; } // If type is "/*" stop processing at "*/" if ($ctype == '*' && $KVString[$i + 1] == "*" && $KVString[$i + 2] == "/") { $i += 2; $comment .= "*/"; break; } $comment .= $KVString[$i]; $i++; } $comment = trim($comment); // Was this comment inline, or after the last item we processed? $where = $lastLine == $line ? 'inline' : 'newline'; // If last line was also a comment, see if we can merge into a multi-line comment // Use the commentLines to see how far back this started $lcl = $line - $commentLines; if (isset($comments[$lcl])) { $lc = $comments[$lcl]; if ($lc['path'] == $lastPath) { $comments[$lcl]['line_text'] .= "\n{$KVLines[$line - 1]}"; $comments[$lcl]['comment'] .= "\n{$comment}"; $comment = ''; $commentLines++; } } // If we have a comment, add it to the list if ($comment) { $comments[$line] = array('path' => $lastPath, 'where' => $where, 'line' => $line, 'line_text' => $KVLines[$line - 1], 'comment' => $comment); } continue; } default: if ($isInQuote) { if ($quoteWhat == "key") { $quoteKey .= $c; } else { $quoteValue .= $c; } } if ($c == "\n") { $line++; } } } if ($debug) { echo "<hr><pre>"; var_dump("stack: ", $stack); } return $stack; }