﻿Index: D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite.i18n.php
===================================================================
--- D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite.i18n.php	(revision 52534)
+++ D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite.i18n.php	(working copy)
@@ -50,20 +50,24 @@
 	/*
 	   Output formatting
 	*/
-	'cite_reference_link_key_with_num' => '$1_$2',
+	'cite_reference_link_key_with_num'      => '$1_$2',
+	'cite_reference_link_key_with_pinpoint' => '$1_$2',
 	# Ids produced by <ref>
-	'cite_reference_link_prefix'       => 'cite_ref-',
-	'cite_reference_link_suffix'       => '',
+	'cite_reference_link_prefix'            => 'cite_ref-',
+	'cite_reference_link_suffix'            => '',
 	# Ids produced by <references>
-	'cite_references_link_prefix'      => 'cite_note-',
-	'cite_references_link_suffix'      => '',
+	'cite_references_link_prefix'           => 'cite_note-',
+	'cite_references_link_suffix'           => '',
 
 	'cite_reference_link'                              => '<sup id="$1" class="reference">[[#$2|<nowiki>[</nowiki>$3<nowiki>]</nowiki>]]</sup>',
+	'cite_references_link_pinpoints'                   => ' <br /><ol class="references" style="list-style-type:lower-alpha">$1</ol>',
+	'cite_references_link_none'                        => '<li id="$1">↑ $2</li>',
 	'cite_references_link_one'                         => '<li id="$1">[[#$2|↑]] $3</li>',
 	'cite_references_link_many'                        => '<li id="$1">↑ $2 $3</li>',
 	'cite_references_link_many_format'                 => '<sup>[[#$1|$2]]</sup>',
 	# An item from this set is passed as $3 in the message above
 	'cite_references_link_many_format_backlink_labels' => 'a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb bc bd be bf bg bh bi bj bk bl bm bn bo bp bq br bs bt bu bv bw bx by bz ca cb cc cd ce cf cg ch ci cj ck cl cm cn co cp cq cr cs ct cu cv cw cx cy cz da db dc dd de df dg dh di dj dk dl dm dn do dp dq dr ds dt du dv dw dx dy dz ea eb ec ed ee ef eg eh ei ej ek el em en eo ep eq er es et eu ev ew ex ey ez fa fb fc fd fe ff fg fh fi fj fk fl fm fn fo fp fq fr fs ft fu fv fw fx fy fz ga gb gc gd ge gf gg gh gi gj gk gl gm gn go gp gq gr gs gt gu gv gw gx gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp jq jr js jt ju jv jw jx jy jz ka kb kc kd ke kf kg kh ki kj kk kl km kn ko kp kq kr ks kt ku kv kw kx ky kz la lb lc ld le lf lg lh li lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md me mf mg mh mi mj mk ml mm mn mo mp mq mr ms mt mu mv mw mx my mz na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv nw nx ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph pi pj pk pl pm pn po pp pq pr ps pt pu pv pw px py pz qa qb qc qd qe qf qg qh qi qj qk ql qm qn qo qp qq qr qs qt qu qv qw qx qy qz ra rb rc rd re rf rg rh ri rj rk rl rm rn ro rp rq rr rs rt ru rv rw rx ry rz sa sb sc sd se sf sg sh si sj sk sl sm sn so sp sq sr ss st su sv sw sx sy sz ta tb tc td te tf tg th ti tj tk tl tm tn to tp tq tr ts tt tu tv tw tx ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz wa wb wc wd we wf wg wh wi wj wk wl wm wn wo wp wq wr ws wt wu wv ww wx wy wz xa xb xc xd xe xf xg xh xi xj xk xl xm xn xo xp xq xr xs xt xu xv xw xx xy xz ya yb yc yd ye yf yg yh yi yj yk yl ym yn yo yp yq yr ys yt yu yv yw yx yy yz za zb zc zd ze zf zg zh zi zj zk zl zm zn zo zp zq zr zs zt zu zv zw zx zy zz',
+	'cite_references_link_pinpoints_backlink_labels'   => 'a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb bc bd be bf bg bh bi bj bk bl bm bn bo bp bq br bs bt bu bv bw bx by bz ca cb cc cd ce cf cg ch ci cj ck cl cm cn co cp cq cr cs ct cu cv cw cx cy cz da db dc dd de df dg dh di dj dk dl dm dn do dp dq dr ds dt du dv dw dx dy dz ea eb ec ed ee ef eg eh ei ej ek el em en eo ep eq er es et eu ev ew ex ey ez fa fb fc fd fe ff fg fh fi fj fk fl fm fn fo fp fq fr fs ft fu fv fw fx fy fz ga gb gc gd ge gf gg gh gi gj gk gl gm gn go gp gq gr gs gt gu gv gw gx gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp jq jr js jt ju jv jw jx jy jz ka kb kc kd ke kf kg kh ki kj kk kl km kn ko kp kq kr ks kt ku kv kw kx ky kz la lb lc ld le lf lg lh li lj lk ll lm ln lo lp lq lr ls lt lu lv lw lx ly lz ma mb mc md me mf mg mh mi mj mk ml mm mn mo mp mq mr ms mt mu mv mw mx my mz na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv nw nx ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph pi pj pk pl pm pn po pp pq pr ps pt pu pv pw px py pz qa qb qc qd qe qf qg qh qi qj qk ql qm qn qo qp qq qr qs qt qu qv qw qx qy qz ra rb rc rd re rf rg rh ri rj rk rl rm rn ro rp rq rr rs rt ru rv rw rx ry rz sa sb sc sd se sf sg sh si sj sk sl sm sn so sp sq sr ss st su sv sw sx sy sz ta tb tc td te tf tg th ti tj tk tl tm tn to tp tq tr ts tt tu tv tw tx ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un uo up uq ur us ut uu uv uw ux uy uz va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz wa wb wc wd we wf wg wh wi wj wk wl wm wn wo wp wq wr ws wt wu wv ww wx wy wz xa xb xc xd xe xf xg xh xi xj xk xl xm xn xo xp xq xr xs xt xu xv xw xx xy xz ya yb yc yd ye yf yg yh yi yj yk yl ym yn yo yp yq yr ys yt yu yv yw yx yy yz za zb zc zd ze zf zg zh zi zj zk zl zm zn zo zp zq zr zs zt zu zv zw zx zy zz',
 	'cite_references_link_many_sep'                    => " ",
 	'cite_references_link_many_and'                    => " ",
 

Index: D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite_body.php
===================================================================
--- D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite_body.php	(revision 52534)
+++ D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite_body.php	(working copy)
@@ -23,34 +23,10 @@
 	 */
 	
 	/**
-	 * Datastructure representing <ref> input, in the format of:
-	 * <code>
-	 * array(
-	 * 	'user supplied' => array(
-	 *		'text' => 'user supplied reference & key',
-	 *		'count' => 1, // occurs twice
-	 * 		'number' => 1, // The first reference, we want
-	 * 		               // all occourances of it to
-	 * 		               // use the same number
-	 *	),
-	 *	0 => 'Anonymous reference',
-	 *	1 => 'Another anonymous reference',
-	 *	'some key' => array(
-	 *		'text' => 'this one occurs once'
-	 *		'count' => 0,
-	 * 		'number' => 4
-	 *	),
-	 *	3 => 'more stuff'
-	 * );
-	 * </code>
-	 *
-	 * 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
-	 *
+	 * Datastructure representing <ref> input, consisting of an array of
+	 * reference groups (array keys are the name of the group), each of which
+	 * comprises an array containing one or more Ref objects.
+	 * 
 	 * @var array
 	 **/
 	var $mRefs = array();
@@ -75,13 +51,22 @@
 	/**
 	 * The backlinks, in order, to pass as $3 to
 	 * 'cite_references_link_many_format', defined in
-	 * 'cite_references_link_many_format_backlink_labels
+	 * 'cite_references_link_many_format_backlink_labels'
 	 *
 	 * @var array
 	 */
 	var $mBacklinkLabels;
 	
 	/**
+	 * The backlinks, in order, to insert into pinpoint reference backlinks
+	 * in $this->referencesFormatEntryNumericBacklinkLabel(). Defined in
+	 * 'cite_references_link_pinpoints_backlink_labels'
+	 * 
+	 * @var array
+	 */
+	var $mPinpointBacklinkLabels;
+	
+	/**
 	 * @var object
 	 */
 	var $mParser;
@@ -128,7 +113,7 @@
 		$this->mParser = $parser;
 		
 		# The key here is the "name" attribute.
-		list($key,$group) = $this->refArg( $argv );
+		list($key,$group,$pinpoint) = $this->refArg( $argv );
 		
 		if( $str === '' ) {
 			# <ref ...></ref>.  This construct is  invalid if
@@ -186,7 +171,7 @@
 			# fers to an existing one.  If it refers to a nonexistent ref,
 			# we'll figure that out later.  Likewise it's definitely valid
 			# if there's any content, regardless of key.
-			return $this->stack( $str, $key, $group );
+			return $this->stack( $str, $key, $group, $pinpoint );
 		}
 
 		# Not clear how we could get here, but something is probably
@@ -208,9 +193,10 @@
 		$cnt = count( $argv );
 		$group = null;
 		$key = null;
+		$pinpoint = null;
 
-		if ( $cnt > 2 )
-			// There should only be one key and one group
+		if ( $cnt > 3 )
+			// There should be at most one key, one group and one pinpoint
 			return false;
 		else if ( $cnt >= 1 ) {
 			if ( isset( $argv['name'] ) ) {
@@ -218,6 +204,14 @@
 				$key = Sanitizer::escapeId( $argv['name'], 'noninitial' );
 				unset( $argv['name']);
 				--$cnt;
+				// Only check for pinpoint references if a key is given (ie, no
+				// pinpoints for anonymous references)
+				if ( isset( $argv['pinpoint'] ) ) {
+					// Pinpoint given
+					$pinpoint = $argv['pinpoint'];
+					unset( $argv['pinpoint'] );
+					--$cnt;
+				}
 			}
 			if ( isset( $argv['group'] ) ){
 				if (! $wgAllowCiteGroups ) return array(false); //remove when groups are fully tested.
@@ -228,14 +222,14 @@
 			}
 
 			if ( $cnt == 0)
-				return array ($key,$group);
+				return array ($key,$group,$pinpoint);
 			else
 				// Invalid key
-				return array(false,false);
+				return array(false,false,false);
 		}
 		else
 			// No key
-			return array(null,$group);
+			return array(null,$group,null);
 	}
 
 	/**
@@ -243,57 +237,54 @@
 	 *
 	 * @param string $str Input from the <ref> tag
 	 * @param mixed $key Argument to the <ref> tag as returned by $this->refArg()
+	 * @param mixed $group Argument to the <ref> tag as returned by $this->refArg()
+	 * @param mixed $pinpoint Argument to the <ref> tag as returned by $this->refArg()
 	 * @return string 
 	 */
-	function stack( $str, $key = null, $group ) {
+	function stack( $str, $key, $group, $pinpoint ) {
 		if (! isset($this->mRefs[$group])) 
 			$this->mRefs[$group]=array();
 		if (! isset($this->mGroupCnt[$group]))
 			$this->mGroupCnt[$group]=0;
 
 		if ( $key === null ) {
-			// No key
-			//$this->mRefs[$group][] = $str;
-			$this->mRefs[$group][] = array('count'=>-1, 'text'=>$str, 'key'=>++$this->mOutCnt);
-
-			return $this->linkRef( $group, $this->mInCnt++ );
+		
+			// No key - anonymous reference
+			$this->mRefs[$group][] = new Ref( null, $group, $str, $pinpoint, -1, $this->mInCnt, ++$this->mOutCnt );
+			$ret = $this->linkRef( $group, $this->mInCnt );
+			$this->mInCnt++;
+			return $ret;
+		
 		} else if ( is_string( $key ) ) {
-			// Valid key
-			if ( ! isset( $this->mRefs[$group][$key] ) || ! is_array( $this->mRefs[$group][$key] ) ) {
+		
+			// Valid key - named reference
+			if ( ! isset( $this->mRefs[$group][$key] ) ) {
 				// First occurance
-				$this->mRefs[$group][$key] = array(
-					'text' => $str,
-					'count' => 0,
-					'key' => ++$this->mOutCnt,
-					'number' => ++$this->mGroupCnt[$group]
-				);
+				$this->mRefs[$group][$key] = new Ref( $key, $group, $str, $pinpoint, 0, ++$this->mGroupCnt[$group], ++$this->mOutCnt );
 				$this->mInCnt++;
-				return
-					$this->linkRef(
-						$group,
-						$key,
-						$this->mRefs[$group][$key]['key']."-".$this->mRefs[$group][$key]['count'],
-						$this->mRefs[$group][$key]['number'],
-						"-".$this->mRefs[$group][$key]['key']
-					);
+				$count = 0;
 			} else {
 				// We've been here before
-				if ( $this->mRefs[$group][$key]['text'] === null && $str !== '' ) {
+				if ( !$this->mRefs[$group][$key]->hasText() && $str !== '' ) {
 					// If no text found before, use this text
-					$this->mRefs[$group][$key]['text'] = $str;
-				};
-				return 
-					$this->linkRef(
-						$group,
-						$key,
-						$this->mRefs[$group][$key]['key']."-".++$this->mRefs[$group][$key]['count'],
-						$this->mRefs[$group][$key]['number'],
-						"-".$this->mRefs[$group][$key]['key']
-					); }
+					$this->mRefs[$group][$key]->setText( $str );
+				}
+				// Increment the reference's internal counter
+				$count = $this->mRefs[$group][$key]->incrementCount( $pinpoint );
+			}
+			
+			return $this->linkRef(
+				$group,
+				$key,
+				$pinpoint,
+				$this->mRefs[$group][$key]->mNumericKey."-".$count,
+				$this->mRefs[$group][$key]->mDisplayNumber,
+				"-".$this->mRefs[$group][$key]->mNumericKey
+				);
+		
+		} else {
+			$this->croak( 'cite_error_stack_invalid_input', serialize( array( $key, $str ) ) );
 		}
-
-		else
-			$this->croak( 'cite_error_stack_invalid_input', serialize( array( $key, $str ) ) );
 	}
 	
 	/**
@@ -354,8 +345,8 @@
 		wfProfileIn( __METHOD__ );
 		wfProfileIn( __METHOD__ .'-entries' );
 		$ent = array();
-		foreach ( $this->mRefs[$group] as $k => $v )
-			$ent[] = $this->referencesFormatEntry( $k, $v );
+		foreach ( $this->mRefs[$group] as $key => $ref )
+			$ent[] = $this->referencesFormatEntry( $key, $ref );
 		
 		$prefix = wfMsgForContentNoTrans( 'cite_references_prefix' );
 		$suffix = wfMsgForContentNoTrans( 'cite_references_suffix' );
@@ -408,68 +399,148 @@
 	 *                   references, array for user-suppplied
 	 * @return string Wikitext
 	 */
-	function referencesFormatEntry( $key, $val ) {
-		// Anonymous reference
-		if ( ! is_array( $val ) )
-			return
-				wfMsgForContentNoTrans(
-					'cite_references_link_one',
-					$this->referencesKey( $key ),
-					$this->refKey( $key ),
-					$val
+	function referencesFormatEntry( $key, &$ref ) {
+	
+		// Retained for parser tests compatability.
+		// TODO: revisit this and possibly remove the parser test, this is
+		// wrong.
+		if( $ref->mText == '' ) {
+			return wfMsgForContentNoTrans(
+				'cite_references_link_one',
+				$this->referencesKey( $key ),
+				$this->refKey( $key, $ref->mCount ),
+				$this->error( 'cite_error_references_no_text', $key )
+			);
+		}
+		
+		// First check is whether this is an anonymous or named reference
+		
+		if( is_null($ref->mKey) ) {
+		
+			// Anomyous reference
+			return wfMsgForContentNoTrans(
+				'cite_references_link_one',
+				$this->referencesKey( $ref->mNumericKey ),
+				$this->refKey( $ref->mNumericKey ),
+				( $ref->mText != '' ? $ref->mText : $this->error( 'cite_error_references_no_text', $key ) )
+			);
+		
+		} else {
+		
+			// Named reference
+			
+			// Set this to null; if there are pinpoint references this will be
+			// replaced with an output string, if not this will have no effect
+			// on the rendered output.
+			$pinlist = '';
+			
+			// The next check is whether there are any pinpoint references, as
+			// these will be processed first.
+			if( !empty($ref->mPinpoints) ) {
+			
+				// Sort the pinpoints using a natural sort algorithm.
+				uksort( $ref->mPinpoints, 'strnatcasecmp' );
+				
+				// The numeric offset of the pinpoint reference currently being
+				// handled. Used for generating backlinks.
+				$j = 0;
+				
+				foreach( $ref->mPinpoints as $pinpoint => $pincount ) {
+				
+					if( $pincount == 0 ) {
+					
+						// Only one use of this pinpoint
+						$pinlist .= wfMsgForContentNoTrans(
+							'cite_references_link_one',
+							$this->referencesKey( $key ."-" . $ref->mNumericKey, null, $pinpoint ),
+							$this->refKey( $key, $ref->mNumericKey."-".$pincount, $pinpoint ),
+							$pinpoint
+						);
+					
+					} else {
+					
+						// Multiple uses of this pinpoint
+						$pinlinks = array();
+						for( $i = 0; $i <= $pincount; ++$i ) {
+							$pinlinks[] = wfMsgForContentNoTrans(
+								'cite_references_link_many_format',
+								$this->refKey( $key, $ref->mNumericKey."-$i", $pinpoint ),
+								$this->referencesFormatEntryPinpointBacklinkLabel( $ref->mDisplayNumber, $i, $pincount, $j ),
+								$this->referencesFormatEntryAlternateBacklinkLabel( $i )
+								);
+						}
+						$pinlist .= wfMsgForContentNoTrans(
+							'cite_references_link_many',
+							$this->referencesKey( $key ."-" . $ref->mNumericKey, null, $pinpoint ),
+							$this->listToText( $pinlinks ),
+							$pinpoint
+						);
+					
+					}
+					
+					// Increment the backlink counter.
+					$j++;
+				
+				}
+				
+				// Finished processing all pinpoints; prepare them to be
+				// inserted into the main list.
+				$pinlist = wfMsgForContentNoTrans( 'cite_references_link_pinpoints', $pinlist );
+			
+			}
+			
+			// Pinpoints (if any) have been processed; now handle basic
+			// instances of this reference and return output.
+			if( is_null($ref->mCount) ) {
+			
+				// No basic instances of the reference; this is valid if there
+				// are pinpoint references.
+				return wfMsgForContentNoTrans(
+					'cite_references_link_none',
+					$this->referencesKey( $key ."-" . $ref->mNumericKey ),
+					( $ref->mText != '' ? $ref->mText . $pinlist : $this->error( 'cite_error_references_no_text', $key ) )
 				);
-		else if ($val['text']=='') return
-				wfMsgForContentNoTrans(
+			
+			} else if( $ref->mCount == 0 ) {
+			
+				// Standalone named reference; format this like an anonymous
+				// reference.
+				return wfMsgForContentNoTrans(
 					'cite_references_link_one',
-					$this->referencesKey( $key ),
-					$this->refKey( $key, $val['count'] ),
-					$this->error( 'cite_error_references_no_text', $key )
+					$this->referencesKey( $key ."-" . $ref->mNumericKey ),
+					$this->refKey( $key, $ref->mNumericKey."-".$ref->mCount ),
+					( $ref->mText != '' ? $ref->mText . $pinlist : $this->error( 'cite_error_references_no_text', $key ) )
 				);
-		if ( $val['count'] < 0 )
-			return
-				wfMsgForContentNoTrans(
-					'cite_references_link_one',
-					$this->referencesKey( $val['key'] ),
-					#$this->refKey( $val['key'], $val['count'] ),
-					$this->refKey( $val['key'] ),
-
-					( $val['text'] != '' ? $val['text'] : $this->error( 'cite_error_references_no_text', $key ) )						
+			
+			} else {
+			
+				// Multiple basic instances of this reference.
+				
+				// Iterate through each instance of the reference and produce a
+				// backlink for each.
+				$links = array();
+				for ( $i = 0; $i <= $ref->mCount; ++$i ) {
+					$links[] = wfMsgForContentNoTrans(
+							'cite_references_link_many_format',
+							$this->refKey( $key, $ref->mNumericKey."-$i" ),
+							$this->referencesFormatEntryNumericBacklinkLabel( $ref->mDisplayNumber, $i, $ref->mCount ),
+							$this->referencesFormatEntryAlternateBacklinkLabel( $i )
+					);
+				}
+				$list = $this->listToText( $links );
+				
+				// Backlinks ready, now produce the output.
+				return wfMsgForContentNoTrans(
+					'cite_references_link_many',
+					$this->referencesKey( $key ."-" . $ref->mNumericKey ),
+					$list,
+					( $ref->mText != '' ? $ref->mText . $pinlist : $this->error( 'cite_error_references_no_text', $key ) )
 				);
-		// Standalone named reference, I want to format this like an
-		// anonymous reference because displaying "1. 1.1 Ref text" is
-		// overkill and users frequently use named references when they
-		// don't need them for convenience
-		else if ( $val['count'] === 0 )
-			return
-				wfMsgForContentNoTrans(
-					'cite_references_link_one',
-					$this->referencesKey( $key ."-" . $val['key'] ),
-					#$this->refKey( $key, $val['count'] ),
-					$this->refKey( $key, $val['key']."-".$val['count'] ),
-					( $val['text'] != '' ? $val['text'] : $this->error( 'cite_error_references_no_text', $key ) )
-				);
-		// Named references with >1 occurrences
-		else {
-			$links = array();
-//for group handling, we have an extra key here.
-			for ( $i = 0; $i <= $val['count']; ++$i ) {
-				$links[] = wfMsgForContentNoTrans(
-						'cite_references_link_many_format',
-						$this->refKey( $key, $val['key']."-$i" ),
-						$this->referencesFormatEntryNumericBacklinkLabel( $val['number'], $i, $val['count'] ),
-						$this->referencesFormatEntryAlternateBacklinkLabel( $i )
-				);
+			
 			}
-
-			$list = $this->listToText( $links );
-
-			return
-				wfMsgForContentNoTrans( 'cite_references_link_many',
-					$this->referencesKey( $key ."-" . $val['key'] ),
-					$list,
-					( $val['text'] != '' ? $val['text'] : $this->error( 'cite_error_references_no_text', $key ) )
-				);
+		
 		}
+	
 	}
 
 	/**
@@ -516,6 +587,37 @@
 	}
 
 	/**
+	 * Generate a numeric backlink for a pinpoint reference, given a base
+	 * number, an offset and the pinpoint's position in the list.
+	 * Since bug #5525, it correctly does 1.9 -> 1.10 as well as 1.099 -> 1.100
+	 *
+	 * @static
+	 *
+	 * @param int $base The base
+	 * @param int $offset The offset
+	 * @param int $max Maximum value expected.
+	 * @param int $pinpos The offset of this pinpoint reference among all pinpoints for this reference.
+	 * @return string
+	 */
+	function referencesFormatEntryPinpointBacklinkLabel( $base, $offset, $max, $pinpos ) {
+		global $wgContLang;
+		if ( !isset( $this->mPinpointBacklinkLabels ) ) {
+			$this->genBacklinkLabels();
+		}
+		if ( isset( $this->mPinpointBacklinkLabels[$pinpos] ) ) {
+			$bl = $this->mPinpointBacklinkLabels[$pinpos];
+		} else {
+			// Feed me!
+			return $this->error( 'cite_error_references_no_backlink_label' );
+		}
+		$scope = strlen( $max );
+		$ret = $wgContLang->formatNum(
+			sprintf("%s%s.%0{$scope}s", $base, $bl, $offset)
+		);
+		return $ret;
+	}
+
+	/**
 	 * Return an id for use in wikitext output based on a key and
 	 * optionally the number of it, used in <references>, not <ref>
 	 * (since otherwise it would link to itself)
@@ -526,11 +628,13 @@
 	 * @param int $num The number of the key
 	 * @return string A key for use in wikitext
 	 */
-	function refKey( $key, $num = null ) {
+	function refKey( $key, $num = null, $pinpoint = null ) {
 		$prefix = wfMsgForContent( 'cite_reference_link_prefix' );
 		$suffix = wfMsgForContent( 'cite_reference_link_suffix' );
 		if ( isset( $num ) )
 			$key = wfMsgForContentNoTrans( 'cite_reference_link_key_with_num', $key, $num );
+		if ( isset( $pinpoint ) )
+			$key = wfMsgForContentNoTrans( 'cite_reference_link_key_with_pinpoint', $key, $pinpoint );
 		
 		return $prefix . $key . $suffix;
 	}
@@ -546,11 +650,13 @@
 	 * @param int $num The number of the key
 	 * @return string A key for use in wikitext
 	 */
-	function referencesKey( $key, $num = null ) {
+	function referencesKey( $key, $num = null, $pinpoint = null ) {
 		$prefix = wfMsgForContent( 'cite_references_link_prefix' );
 		$suffix = wfMsgForContent( 'cite_references_link_suffix' );
 		if ( isset( $num ) )
 			$key = wfMsgForContentNoTrans( 'cite_reference_link_key_with_num', $key, $num );
+		if ( isset( $pinpoint ) )
+			$key = wfMsgForContentNoTrans( 'cite_reference_link_key_with_pinpoint', $key, $pinpoint );
 		
 		return $prefix . $key . $suffix;
 	}
@@ -567,14 +673,14 @@
 	 *                   the same named reference.
 	 * @return string
 	 */
-	function linkRef( $group, $key, $count = null, $label = null, $subkey = '' ) {
+	function linkRef( $group, $key, $pinpoint = null, $count = null, $label = null, $subkey = '' ) {
 		global $wgContLang;
 		return
 			$this->parse(
 				wfMsgForContentNoTrans(
 					'cite_reference_link',
-					$this->refKey( $key, $count ),
-					$this->referencesKey( $key . $subkey ),
+					$this->refKey( $key, $count, $pinpoint ),
+					$this->referencesKey( $key . $subkey, null, $pinpoint ),
 					(($group == CITE_DEFAULT_GROUP)?'':"$group ").$wgContLang->formatNum( is_null( $label ) ? ++$this->mGroupCnt[$group] : $label )
 				)
 			);
@@ -670,6 +776,8 @@
 		wfProfileIn( __METHOD__ );
 		$text = wfMsgForContentNoTrans( 'cite_references_link_many_format_backlink_labels' );
 		$this->mBacklinkLabels = preg_split( '#[\n\t ]#', $text );
+		$text = wfMsgForContentNoTrans( 'cite_references_link_pinpoints_backlink_labels' );
+		$this->mPinpointBacklinkLabels = preg_split( '#[\n\t ]#', $text );
 		wfProfileOut( __METHOD__ );
 	}
 

Index: D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite_ref.php
===================================================================
--- D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite_ref.php	(revision 0)
+++ D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite_ref.php	(revision 0)
@@ -0,0 +1,161 @@
+<?php
+
+/**#@+
+ * A parser extension that adds two tags, <ref> and <references> for adding
+ * citations to pages
+ *
+ * @addtogroup Extensions
+ *
+ * @link http://meta.wikimedia.org/wiki/Cite/Cite.php Documentation
+ * @link http://www.w3.org/TR/html4/struct/text.html#edef-CITE <cite> definition in HTML
+ * @link http://www.w3.org/TR/2005/WD-xhtml2-20050527/mod-text.html#edef_text_cite <cite> definition in XHTML 2.0
+ *
+ * @bug 4579
+ *
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
+ */
+
+class Ref {
+	/**#@+
+	 * @access private
+	 */
+	
+	/**
+	 * The reference key. For named references this is drawn from the "name"
+	 * parameter to the <ref> tag, otherwise it is a number, identical to
+	 * $this->mNumericKey.
+	 * 
+	 * @var string
+	 */
+	var $mKey = null;
+	
+	/**
+	 * The group this reference belongs to, drawn from the "group" parameter
+	 * to the <ref> tag. Filled with CITE_DEFAULT_GROUP if a group is not
+	 * specified.
+	 * 
+	 * @var string
+	 */
+	var $mGroup = null;
+	
+	/**
+	 * The text of the reference (ie, the contents of the <ref> tag).
+	 * 
+	 * @var string
+	 */
+	var $mText = '';
+	
+	/**
+	 * The internal counter for this reference; how many times it has been used
+	 * in the article text. Relevant for named references only. This is used
+	 * when a pinpoint reference is not supplied.
+	 * 
+	 * @var string
+	 */
+	var $mCount = null;
+	
+	/**
+	 * Collection of internal counters for pinpoint references to this
+	 * reference. An array, with the keys being the pinpoint reference and the
+	 * values being the counters.
+	 * 
+	 * @var array
+	 */
+	var $mPinpoints = array();
+	
+	/**
+	 * The display number for this reference, used in the XHTML that replaces
+	 * the <ref> tag. This is the number that is displayed to the user.
+	 * 
+	 * @var string
+	 */
+	var $mDisplayNumber = 0;
+	
+	/**
+	 * The reference's numeric key. Every reference has a different numeric
+	 * key, regardless of the group that it is in.
+	 * 
+	 * @var string
+	 */
+	var $mNumericKey = 0;
+	
+	/**#@-*/
+	
+	/**
+	 * Constructor
+	 * 
+	 * @param string $key
+	 * @param string $group
+	 * @param string $text
+	 * @param string $pinpoint
+	 * @param int $count
+	 * @param int $displaynumber
+	 * @param int $numkey
+	 */
+	function Ref( $key, $group, $text, $pinpoint, $count, $displaynumber, $numkey ) {
+	
+		$this->mKey = $key;
+		$this->mGroup = $group;
+		$this->mText = $text;
+		$this->mDisplayNumber = $displaynumber;
+		$this->mNumericKey = $numkey;
+		
+		if( !is_null($pinpoint) ) {
+			// A pinpoint reference has been supplied, initialise the specific
+			// counter for that pinpoint.
+			$this->mPinpoints[$pinpoint] = 0;
+		} else {
+			// No pinpoint supplied, initialise the general counter
+			$this->mCount = $count;
+		}
+	
+	}
+	
+	/**
+	 * Checks whether there is any text set for this reference.
+	 * 
+	 * @return bool
+	 */
+	function hasText() {
+		return !is_null( $this->mText );
+	}
+	
+	/**
+	 * Sets the text for this reference.
+	 * 
+	 * @param string $text The text to be stored
+	 */
+	function setText( $text ) {
+		$this->mText = $text;
+	}
+	
+	/**
+	 * Increments the relevant internal counter (a pinpoint reference counter,
+	 * if a pinpoint reference has been given, otherwise the general counter).
+	 * 
+	 * @param string $pinpoint The pinpoint reference
+	 * @return int The value of the counter just incremented
+	 */
+	function incrementCount( $pinpoint ) {
+		if( !is_null($pinpoint) ) {
+			// A pinpoint reference has been supplied, increment the specific
+			// counter for that pinpoint.
+			if( isset( $this->mPinpoints[$pinpoint] ) ) {
+				$count = ++$this->mPinpoints[$pinpoint];
+			} else {
+				$this->mPinpoints[$pinpoint] = 0;
+				$count = 0;
+			}
+		} else {
+			// No pinpoint supplied, increment the general counter
+			$count = ++$this->mCount;
+		}
+		return $count;
+	}
+	
+	/**#@-*/
+}
+
+?>
\ No newline at end of file

Index: D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite.php
===================================================================
--- D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite.php	(revision 52534)
+++ D:/Stephen/work/mediawiki/phase3/extensions/Cite/Cite.php	(working copy)
@@ -35,6 +35,7 @@
 $wgParserTestFiles[] = dirname( __FILE__ ) . "/citeParserTests.txt";
 $wgExtensionMessagesFiles['Cite'] = dirname( __FILE__ ) . "/Cite.i18n.php";
 $wgAutoloadClasses['Cite'] = dirname( __FILE__ ) . "/Cite_body.php";
+$wgAutoloadClasses['Ref'] = dirname( __FILE__ ) . "/Cite_ref.php";
 $wgSpecialPageGroups['Cite'] = 'pagetools';
 
 define( 'CITE_DEFAULT_GROUP', '');
