Use Html class instead of Xml where possible in Special:Contributions
[lhc/web/wiklou.git] / includes / ConfEditor.php
index a1a3431..d304e65 100644 (file)
@@ -1,6 +1,26 @@
 <?php
+/**
+ * Configuration file editor.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
 
-/** 
+/**
  * This is a state machine style parser with two internal stacks:
  *   * A next state stack, which determines the state the machine will progress to next
  *   * A path stack, which keeps track of the logical location in the file.
@@ -40,8 +60,8 @@ class ConfEditor {
        /** The previous ConfEditorToken object */
        var $prevToken;
 
-       /** 
-        * The state machine stack. This is an array of strings where the topmost 
+       /**
+        * The state machine stack. This is an array of strings where the topmost
         * element will be popped off and become the next parser state.
         */
        var $stateStack;
@@ -66,7 +86,7 @@ class ConfEditor {
        var $pathStack;
 
        /**
-        * The elements of the top of the pathStack for every path encountered, indexed 
+        * The elements of the top of the pathStack for every path encountered, indexed
         * by slash-separated path.
         */
        var $pathInfo;
@@ -77,13 +97,17 @@ class ConfEditor {
        var $serial;
 
        /**
-        * Editor state. This consists of the internal copy/insert operations which 
+        * Editor state. This consists of the internal copy/insert operations which
         * are applied to the source string to obtain the destination string.
         */
        var $edits;
 
        /**
         * Simple entry point for command-line testing
+        *
+        * @param $text string
+        *
+        * @return string
         */
        static function test( $text ) {
                try {
@@ -103,7 +127,7 @@ class ConfEditor {
        }
 
        /**
-        * Edit the text. Returns the edited text. 
+        * Edit the text. Returns the edited text.
         * @param $ops Array of operations.
         *
         * Operations are given as an associative array, with members:
@@ -114,20 +138,20 @@ class ConfEditor {
         *
         * delete
         *    Deletes an array element or statement with the specified path.
-        *    e.g. 
+        *    e.g.
         *        array('type' => 'delete', 'path' => '$foo/bar/baz' )
         *    is equivalent to the runtime PHP code:
         *        unset( $foo['bar']['baz'] );
         *
         * set
-        *    Sets the value of an array element. If the element doesn't exist, it 
-        *    is appended to the array. If it does exist, the value is set, with 
+        *    Sets the value of an array element. If the element doesn't exist, it
+        *    is appended to the array. If it does exist, the value is set, with
         *    comments and indenting preserved.
         *
         * append
         *    Appends a new element to the end of the array. Adds a trailing comma.
         *    e.g.
-        *        array( 'type' => 'append', 'path', '$foo/bar', 
+        *        array( 'type' => 'append', 'path', '$foo/bar',
         *            'key' => 'baz', 'value' => "'x'" )
         *    is like the PHP code:
         *        $foo['bar']['baz'] = 'x';
@@ -135,6 +159,8 @@ class ConfEditor {
         * insert
         *    Insert a new element at the start of the array.
         *
+        * @throws MWException
+        * @return string
         */
        public function edit( $ops ) {
                $this->parse();
@@ -176,7 +202,7 @@ class ConfEditor {
                                // Has it got a comma already?
                                if ( strpos( $lastEltPath, '@extra' ) === false && !$lastEltInfo['hasComma'] ) {
                                        // No comma, insert one after the value region
-                                       list( $start, $end ) = $this->findValueRegion( $lastEltPath );
+                                       list( , $end ) = $this->findValueRegion( $lastEltPath );
                                        $this->replaceSourceRegion( $end - 1, $end - 1, ',' );
                                }
 
@@ -184,10 +210,10 @@ class ConfEditor {
                                list( $start, $end ) = $this->findDeletionRegion( $lastEltPath );
 
                                if ( $key === null ) {
-                                       list( $indent, $arrowIndent ) = $this->getIndent( $start );
+                                       list( $indent, ) = $this->getIndent( $start );
                                        $textToInsert = "$indent$value,";
                                } else {
-                                       list( $indent, $arrowIndent ) = 
+                                       list( $indent, $arrowIndent ) =
                                                $this->getIndent( $start, $key, $lastEltInfo['arrowByte'] );
                                        $textToInsert = "$indent$key$arrowIndent=> $value,";
                                }
@@ -202,15 +228,15 @@ class ConfEditor {
                                if ( $firstEltPath === false ) {
                                        throw new MWException( "Can't find array element of \"$path\"" );
                                }
-                               list( $start, $end ) = $this->findDeletionRegion( $firstEltPath );
+                               list( $start, ) = $this->findDeletionRegion( $firstEltPath );
                                $info = $this->pathInfo[$firstEltPath];
 
                                // Make the text to insert
                                if ( $key === null ) {
-                                       list( $indent, $arrowIndent ) = $this->getIndent( $start );
+                                       list( $indent, ) = $this->getIndent( $start );
                                        $textToInsert = "$indent$value,";
                                } else {
-                                       list( $indent, $arrowIndent ) = 
+                                       list( $indent, $arrowIndent ) =
                                                $this->getIndent( $start, $key, $info['arrowByte'] );
                                        $textToInsert = "$indent$key$arrowIndent=> $value,";
                                }
@@ -239,13 +265,13 @@ class ConfEditor {
                try {
                        $this->parse();
                } catch ( ConfEditorParseError $e ) {
-                       throw new MWException( 
+                       throw new MWException(
                                "Sorry, ConfEditor broke the file during editing and it won't parse anymore: " .
                                $e->getMessage() );
                }
                return $out;
        }
-       
+
        /**
         * Get the variables defined in the text
         * @return array( varname => value )
@@ -266,7 +292,7 @@ class ConfEditor {
                                strlen( $trimmedPath ) - strlen( $name ) );
                        if( substr( $parentPath, -1 ) == '/' )
                                $parentPath = substr( $parentPath, 0, -1 );
-                       
+
                        $value = substr( $this->text, $data['valueStartByte'],
                                $data['valueEndByte'] - $data['valueStartByte']
                        );
@@ -275,7 +301,7 @@ class ConfEditor {
                }
                return $vars;
        }
-       
+
        /**
         * Set a value in an array, unless it's set already. For instance,
         * setVar( $arr, 'foo/bar', 'baz', 3 ); will set
@@ -298,7 +324,7 @@ class ConfEditor {
                if ( !isset( $target[$key] ) )
                        $target[$key] = $value;
        }
-       
+
        /**
         * Parse a scalar value in PHP
         * @return mixed Parsed value
@@ -306,14 +332,14 @@ class ConfEditor {
        function parseScalar( $str ) {
                if ( $str !== '' && $str[0] == '\'' )
                        // Single-quoted string
-                       // @todo Fixme: trim() call is due to mystery bug where whitespace gets
+                       // @todo FIXME: trim() call is due to mystery bug where whitespace gets
                        // appended to the token; without it we ended up reading in the
                        // extra quote on the end!
                        return strtr( substr( trim( $str ), 1, -1 ),
                                array( '\\\'' => '\'', '\\\\' => '\\' ) );
-               if ( $str !== '' && @$str[0] == '"' )
+               if ( $str !== '' && $str[0] == '"' )
                        // Double-quoted string
-                       // @todo Fixme: trim() call is due to mystery bug where whitespace gets
+                       // @todo FIXME: trim() call is due to mystery bug where whitespace gets
                        // appended to the token; without it we ended up reading in the
                        // extra quote on the end!
                        return stripcslashes( substr( trim( $str ), 1, -1 ) );
@@ -336,7 +362,7 @@ class ConfEditor {
                // Split all copy operations with a source corresponding to the region
                // in question.
                $newEdits = array();
-               foreach ( $this->edits as $i => $edit ) {
+               foreach ( $this->edits as $edit ) {
                        if ( $edit[0] !== 'copy' ) {
                                $newEdits[] = $edit;
                                continue;
@@ -364,9 +390,12 @@ class ConfEditor {
        }
 
        /**
-        * Finds the source byte region which you would want to delete, if $pathName 
-        * was to be deleted. Includes the leading spaces and tabs, the trailing line 
+        * Finds the source byte region which you would want to delete, if $pathName
+        * was to be deleted. Includes the leading spaces and tabs, the trailing line
         * break, and any comments in between.
+        * @param $pathName
+        * @throws MWException
+        * @return array
         */
        function findDeletionRegion( $pathName ) {
                if ( !isset( $this->pathInfo[$pathName] ) ) {
@@ -419,11 +448,14 @@ class ConfEditor {
        }
 
        /**
-        * Find the byte region in the source corresponding to the value part. 
-        * This includes the quotes, but does not include the trailing comma 
-        * or semicolon. 
+        * Find the byte region in the source corresponding to the value part.
+        * This includes the quotes, but does not include the trailing comma
+        * or semicolon.
         *
         * The end position is the past-the-end (end + 1) value as per convention.
+        * @param $pathName
+        * @throws MWException
+        * @return array
         */
        function findValueRegion( $pathName ) {
                if ( !isset( $this->pathInfo[$pathName] ) ) {
@@ -440,6 +472,7 @@ class ConfEditor {
         * Find the path name of the last element in the array.
         * If the array is empty, this will return the \@extra interstitial element.
         * If the specified path is not found or is not an array, it will return false.
+        * @return bool|int|string
         */
        function findLastArrayElement( $path ) {
                // Try for a real element
@@ -472,10 +505,11 @@ class ConfEditor {
                return $extraPath;
        }
 
-       /*
+       /**
         * Find the path name of first element in the array.
         * If the array is empty, this will return the \@extra interstitial element.
         * If the specified path is not found or is not an array, it will return false.
+        * @return bool|int|string
         */
        function findFirstArrayElement( $path ) {
                // Try for an ordinary element
@@ -500,6 +534,7 @@ class ConfEditor {
        /**
         * Get the indent string which sits after a given start position.
         * Returns false if the position is not at the start of the line.
+        * @return array
         */
        function getIndent( $pos, $key = false, $arrowPos = false ) {
                $arrowIndent = ' ';
@@ -510,7 +545,6 @@ class ConfEditor {
                        $indent = false;
                }
                if ( $indent !== false && $arrowPos !== false ) {
-                       $textToInsert = "$indent$key ";
                        $arrowIndentLength = $arrowPos - $pos - $indentLength - strlen( $key );
                        if ( $arrowIndentLength > 0 ) {
                                $arrowIndent = str_repeat( ' ', $arrowIndentLength );
@@ -520,7 +554,7 @@ class ConfEditor {
        }
 
        /**
-        * Run the parser on the text. Throws an exception if the string does not 
+        * Run the parser on the text. Throws an exception if the string does not
         * match our defined subset of PHP syntax.
         */
        public function parse() {
@@ -537,7 +571,7 @@ class ConfEditor {
 
                        switch ( $state ) {
                        case 'file':
-                               $token = $this->expect( T_OPEN_TAG );
+                               $this->expect( T_OPEN_TAG );
                                $token = $this->skipSpace();
                                if ( $token->isEnd() ) {
                                        break 2;
@@ -707,7 +741,7 @@ class ConfEditor {
        }
 
        /**
-        * Set the parse position. Do not call this except from firstToken() and 
+        * Set the parse position. Do not call this except from firstToken() and
         * nextToken(), there is more to update than just the position.
         */
        protected function setPos( $pos ) {
@@ -722,6 +756,7 @@ class ConfEditor {
 
        /**
         * Create a ConfEditorToken from an element of token_get_all()
+        * @return ConfEditorToken
         */
        function newTokenObj( $internalToken ) {
                if ( is_array( $internalToken ) ) {
@@ -773,6 +808,7 @@ class ConfEditor {
        /**
         * Get the token $offset steps ahead of the current position.
         * $offset may be negative, to get tokens behind the current position.
+        * @return ConfEditorToken
         */
        function getTokenAhead( $offset ) {
                $pos = $this->pos + $offset;
@@ -801,7 +837,7 @@ class ConfEditor {
                if ( $this->currentToken && $this->currentToken->type == $type ) {
                        return $this->nextToken();
                } else {
-                       $this->error( "expected " . $this->getTypeName( $type ) . 
+                       $this->error( "expected " . $this->getTypeName( $type ) .
                                ", got " . $this->getTypeName( $this->currentToken->type ) );
                }
        }
@@ -818,6 +854,7 @@ class ConfEditor {
 
        /**
         * Pop a state from the state stack.
+        * @return mixed
         */
        function popState() {
                return array_pop( $this->stateStack );
@@ -826,6 +863,7 @@ class ConfEditor {
        /**
         * Returns true if the user input path is valid.
         * This exists to allow "/" and "@" to be reserved for string path keys
+        * @return bool
         */
        function validatePath( $path ) {
                return strpos( $path, '/' ) === false && substr( $path, 0, 1 ) != '@';
@@ -876,7 +914,7 @@ class ConfEditor {
        }
 
        /**
-        * Go to the next path on the same level. This ends the current path and 
+        * Go to the next path on the same level. This ends the current path and
         * starts a new one. If $path is \@next, the new path is set to the next
         * numeric array element.
         */
@@ -890,7 +928,7 @@ class ConfEditor {
                } else {
                        $this->pathStack[$i]['name'] = $path;
                }
-               $this->pathStack[$i] = 
+               $this->pathStack[$i] =
                        array(
                                'startByte' => $this->byteNum,
                                'startToken' => $this->pos,
@@ -946,6 +984,7 @@ class ConfEditor {
 
        /**
         * Get a readable name for the given token type.
+        * @return string
         */
        function getTypeName( $type ) {
                if ( is_int( $type ) ) {
@@ -956,9 +995,10 @@ class ConfEditor {
        }
 
        /**
-        * Looks ahead to see if the given type is the next token type, starting 
-        * from the current position plus the given offset. Skips any intervening 
+        * Looks ahead to see if the given type is the next token type, starting
+        * from the current position plus the given offset. Skips any intervening
         * whitespace.
+        * @return bool
         */
        function isAhead( $type, $offset = 0 ) {
                $ahead = $offset;
@@ -993,8 +1033,8 @@ class ConfEditor {
                $out = '';
                foreach ( $this->tokens as $token ) {
                        $obj = $this->newTokenObj( $token );
-                       $out .= sprintf( "%-28s %s\n", 
-                               $this->getTypeName( $obj->type ), 
+                       $out .= sprintf( "%-28s %s\n",
+                               $this->getTypeName( $obj->type ),
                                addcslashes( $obj->text, "\0..\37" ) );
                }
                echo "<pre>" . htmlspecialchars( $out ) . "</pre>";
@@ -1009,7 +1049,7 @@ class ConfEditorParseError extends MWException {
        function __construct( $editor, $msg ) {
                $this->lineNum = $editor->lineNum;
                $this->colNum = $editor->colNum;
-               parent::__construct( "Parse error on line {$editor->lineNum} " . 
+               parent::__construct( "Parse error on line {$editor->lineNum} " .
                        "col {$editor->colNum}: $msg" );
        }
 
@@ -1029,7 +1069,7 @@ class ConfEditorParseError extends MWException {
  */
 class ConfEditorToken {
        var $type, $text;
-       
+
        static $scalarTypes = array( T_LNUMBER, T_DNUMBER, T_STRING, T_CONSTANT_ENCAPSED_STRING );
        static $skipTypes = array( T_WHITESPACE, T_COMMENT, T_DOC_COMMENT );