+/**
+ * Stack class to help Preprocessor::preprocessToObj()
+ */
+class PPDStack {
+ var $stack, $rootAccum, $top;
+ var $out;
+ static $false = false;
+
+ function __construct() {
+ $this->stack = array();
+ $this->top = false;
+ $this->rootAccum = '';
+ $this->accum =& $this->rootAccum;
+ }
+
+ function count() {
+ return count( $this->stack );
+ }
+
+ function &getAccum() {
+ return $this->accum;
+ }
+
+ function getCurrentPart() {
+ if ( $this->top === false ) {
+ return false;
+ } else {
+ return $this->top->getCurrentPart();
+ }
+ }
+
+ function push( $data ) {
+ if ( $data instanceof PPDStackElement ) {
+ $this->stack[] = $data;
+ } else {
+ $this->stack[] = new PPDStackElement( $data );
+ }
+ $this->top = $this->stack[ count( $this->stack ) - 1 ];
+ $this->accum =& $this->top->getAccum();
+ }
+
+ function pop() {
+ if ( !count( $this->stack ) ) {
+ throw new MWException( __METHOD__.': no elements remaining' );
+ }
+ $temp = array_pop( $this->stack );
+
+ if ( count( $this->stack ) ) {
+ $this->top = $this->stack[ count( $this->stack ) - 1 ];
+ $this->accum =& $this->top->getAccum();
+ } else {
+ $this->top = self::$false;
+ $this->accum =& $this->rootAccum;
+ }
+ return $temp;
+ }
+
+ function addPart( $s = '' ) {
+ $this->top->addPart( $s );
+ $this->accum =& $this->top->getAccum();
+ }
+
+ function getFlags() {
+ if ( !count( $this->stack ) ) {
+ return array(
+ 'findEquals' => false,
+ 'findPipe' => false,
+ 'inHeading' => false,
+ );
+ } else {
+ return $this->top->getFlags();
+ }
+ }
+}
+
+class PPDStackElement {
+ var $open, // Opening character (\n for heading)
+ $close, // Matching closing character
+ $count, // Number of opening characters found (number of "=" for heading)
+ $parts, // Array of PPDPart objects describing pipe-separated parts.
+ $lineStart; // True if the open char appeared at the start of the input line. Not set for headings.
+
+ function __construct( $data = array() ) {
+ $this->parts = array( new PPDPart );
+
+ foreach ( $data as $name => $value ) {
+ $this->$name = $value;
+ }
+ }
+
+ function &getAccum() {
+ return $this->parts[count($this->parts) - 1]->out;
+ }
+
+ function addPart( $s = '' ) {
+ $this->parts[] = new PPDPart( $s );
+ }
+
+ function getCurrentPart() {
+ return $this->parts[count($this->parts) - 1];
+ }
+
+ function getFlags() {
+ $partCount = count( $this->parts );
+ $findPipe = $this->open != "\n" && $this->open != '[';
+ return array(
+ 'findPipe' => $findPipe,
+ 'findEquals' => $findPipe && $partCount > 1 && !isset( $this->parts[$partCount - 1]->eqpos ),
+ 'inHeading' => $this->open == "\n",
+ );
+ }
+
+ /**
+ * Get the output string that would result if the close is not found.
+ */
+ function breakSyntax( $openingCount = false ) {
+ if ( $this->open == "\n" ) {
+ $s = $this->parts[0]->out;
+ } else {
+ if ( $openingCount === false ) {
+ $openingCount = $this->count;
+ }
+ $s = str_repeat( $this->open, $openingCount );
+ $first = true;
+ foreach ( $this->parts as $part ) {
+ if ( $first ) {
+ $first = false;
+ } else {
+ $s .= '|';
+ }
+ $s .= $part->out;
+ }
+ }
+ return $s;
+ }
+}
+
+class PPDPart {
+ var $out; // Output accumulator string
+
+ // Optional member variables:
+ // eqpos Position of equals sign in output accumulator
+ // commentEnd Past-the-end input pointer for the last comment encountered
+ // visualEnd Past-the-end input pointer for the end of the accumulator minus comments
+
+ function __construct( $out = '' ) {
+ $this->out = $out;
+ }
+}
+