* array(
* 'user supplied' => array(
* 'text' => 'user supplied reference & key',
* 'count' => 1, // occurs twice
* ),
* 0 => 'Anonymous reference',
* 1 => 'Another anonymous reference',
* 'some key' => array(
* 'text' => 'this one occurs once'
* 'count' => 0
* ),
* 3 => 'more stuff'
* );
*
*
* This works because:
* * PHP's datastructures are guarenteed to be returned in the
* order that things are inserted into them (unless you mess
* with that)
* * User supplied keys can't be integers, therefore avoiding
* conflict with anonymous keys
*
* @var array
**/
var $mRefs = array();
/**
* Count for user displayed output (ref[1], ref[2], ...)
*
* @var int
*/
var $mOutCnt = 0;
/**
* Internal counter for anonymous references, seperate from
* $mOutCnt because anonymous references won't increment it,
* but will incremement $mOutCnt
*
* @var int
*/
var $mInCnt = 0;
/**
* @var object
*/
var $mParser, $mParserOptions;
/**#@-*/
/**
* Constructor
*/
function Cite() {
$this->setHooks();
$this->genParser();
}
/**#@+ @access private */
/**
* Callback function for
*
* @param string $str Input
* @param array $argv Arguments
* @return string
*/
function ref( $str, $argv ) {
$key = $this->refArg( $argv );
if ( $str !== null ) {
if ( $str === '' )
return $this->error( CITE_ERROR_REF_NO_INPUT );
if ( is_string( $key ) )
// I don't want keys in the form of /^[0-9]+$/ because they would
// conflict with the php datastructure I'm using, besides, why specify
// a manual key if it's just going to be any old integer?
if ( sprintf( '%d', $key ) === (string)$key )
return $this->error( CITE_ERROR_REF_NUMERIC_KEY );
else
return $this->stack( $str, $key );
else if ( $key === null )
return $this->stack( $str );
else if ( $key === false )
return $this->error( CITE_ERROR_REF_TOO_MANY_KEYS );
else
$this->croak( CITE_ERROR_KEY_INVALID_1, serialize( $key ) );
} else if ( $str === null ) {
if ( is_string( $key ) )
if ( sprintf( '%d', $key ) === (string)$key )
return $this->error( CITE_ERROR_REF_NUMERIC_KEY );
else
return $this->stack( $str, $key );
else if ( $key === false )
return $this->error( CITE_ERROR_REF_TOO_MANY_KEYS );
else if ( $key === null )
return $this->error( CITE_ERROR_REF_NO_KEY );
else
$this->croak( CITE_ERROR_KEY_INVALID_2, serialize( $key ) );
} else
$this->croak( CITE_ERROR_STR_INVALID, serialize( $str ) );
}
/**
* Parse the arguments to the tag
*
* @param array $argv The argument vector
*
* @return mixed false on invalid input, a string on valid
* input and null on no input
*/
function refArg( $argv ) {
if ( count( $argv ) > 1 )
// There should only be one key
return false;
else if ( count( $argv ) == 1 )
// Key given.
return array_shift( $argv );
else
// No key
return null;
}
/**
* Populate $this->mRefs based on input and arguments to
*
* @param string $str Input from the tag
* @param mixed $key Argument to the tag as returned by $this->refArg()
* @return string
*/
function stack( $str, $key = null ) {
if ( $key === null ) {
// No key
$this->mRefs[] = $str;
return $this->linkRef( $this->mInCnt++ );
} else if ( is_string( $key ) )
// Valid key
if ( ! @is_array( $this->mRefs[$key] ) ) {
// First occourance
$this->mRefs[$key] = array(
'text' => $str,
'count' => 0
);
return $this->linkRef( $key, 0 );
} else
// We've been here before
return $this->linkRef( $key, ++$this->mRefs[$key]['count'] );
else
$this->croak( CITE_ERROR_STACK_INVALID_INPUT, serialize( array( $key, $str ) ) );
}
/**
* Callback function for if it isn't already, fix that and return the fixed text * * @param string $text The text to fix * @return string The fixed text */ function fixTidy( $text ) { global $wgUseTidy; if ( ! $wgUseTidy ) return $text; else { $text = preg_replace( '#^
\s*#', '', $text ); $text = preg_replace( '#\s*
\s*#', '', $text ); wfDebugLog( 'misc', "'''$text'''" ); return $text; } } /** * $wgOut->parse() has issues with the elements defined in * setHooks() being used inside includes templates so I'm * rolling my own parser */ function genParser() { $this->mParser = new Parser; $this->mParserOptions = new ParserOptions; } /** * Initialize the parser hooks */ function setHooks() { global $wgParser; $wgParser->setHook( 'ref' , array( &$this, 'ref' ) ); $wgParser->setHook( 'references' , array( &$this, 'references' ) ); } /** * Return an error message based on an error ID * * @param int $id ID for the error * @return string XHTML ready for output */ function error( $id ) { if ( $id > 0 ) // User errors are positive return $this->parse( wfMsgforContent( 'cite_error', $id, wfMsgForContent( "cite_error_$id" ) ) ); else if ( $id < 0 ) return wfMsgforContent( 'cite_error', $id ); } /** * Die with a backtrace if something happens in the code which * shouldn't have * * @param int $error ID for the error * @param string $data Serialized error data */ function croak( $error, $data ) { wfDebugDieBacktrace( wfMsgForContent( 'cite_croak', $this->error( $error ), $data ) ); } /**#@-*/ } new PersistentObject( new Cite ); } /**#@-*/